{
  "components": {
    "schemas": {
      "Account": {
        "properties": {
          "allow_xlarge": {
            "type": "boolean"
          },
          "closed_at": {
            "description": "Closed (`POST /account/close`): unix seconds. Reopen before `erase_at`.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "data_retention": {
            "$ref": "#/components/schemas/DataRetention",
            "default": {
              "monitoring_off": false,
              "snapshots_off": false,
              "zero_data_retention": false
            }
          },
          "deletion_operation": {
            "description": "The closing's deletion operation (`dop_…`, `GET /deletion-operations/{id}`).",
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": "string"
          },
          "erase_at": {
            "description": "When a closed account's data is erased for good (closed_at + 30 days).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "max_sandboxes": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "org": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/OrgSummary"
              },
              {
                "type": "null"
              }
            ],
            "description": "The organization this request acted in (`X-Froog-Org`, or the active one); absent in your personal workspace. `id` and `email` stay yours."
          }
        },
        "required": [
          "allow_xlarge",
          "email",
          "id",
          "max_sandboxes"
        ],
        "type": "object"
      },
      "AccountClosing": {
        "description": "`POST /v1/account/close` and `POST /v1/account/reopen`.",
        "properties": {
          "account": {
            "$ref": "#/components/schemas/Account"
          },
          "operation": {
            "$ref": "#/components/schemas/DeletionOperation"
          }
        },
        "required": [
          "account",
          "operation"
        ],
        "type": "object"
      },
      "AddAiCredential": {
        "description": "Add an account to a profile (`POST /v1/ai/profiles/{profile}/credentials`). A provider that already has one gets another, used when the first hits a rate or usage limit.",
        "properties": {
          "base_url": {
            "description": "Custom APIs: an https:// URL with a public DNS name. Bedrock: the AWS region (default us-east-1) goes in `region`.",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "description": "Custom APIs: the variable name (A-Z, 0-9, _; not a provider's).",
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "description": "anthropic, openai, gemini, deepseek, mistral, openrouter, xai, bedrock or custom.",
            "type": "string"
          },
          "region": {
            "description": "Bedrock: the AWS region, e.g. us-west-2.",
            "type": [
              "string",
              "null"
            ]
          },
          "secret_header": {
            "description": "Custom APIs: the header the proxy puts the secret in, and only there (default `Authorization` with `Bearer `). The placeholder anywhere else in the request is removed.",
            "type": [
              "string",
              "null"
            ]
          },
          "secret_prefix": {
            "description": "Custom APIs: what comes before the secret in the header, e.g. `Bearer ` or `Token ` (default `Bearer ` when neither `secret_header` nor `secret_query` is given, else none).",
            "type": [
              "string",
              "null"
            ]
          },
          "secret_query": {
            "description": "Custom APIs: put the secret in this query parameter instead of a header (e.g. `api_key`).",
            "type": [
              "string",
              "null"
            ]
          },
          "value": {
            "description": "The key: one token of up to 8192 printable characters. Bedrock: a Bedrock API key, or `ACCESS_KEY_ID:SECRET_ACCESS_KEY[:SESSION_TOKEN]`.",
            "type": "string"
          }
        },
        "required": [
          "provider",
          "value"
        ],
        "type": "object"
      },
      "AddSshKey": {
        "properties": {
          "name": {
            "type": "string"
          },
          "public_key": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "public_key"
        ],
        "type": "object"
      },
      "AgentEvent": {
        "description": "One event of the agent's work.\n\n`type`: `status` (data: status, error), `text` (content, partial), `tool_call` (name, input, id), `tool_result` (output, is_error, id), `steer` (message, native, mode), `log` (a line the harness printed that isn't an event), `error` (message).",
        "properties": {
          "at": {
            "description": "Unix milliseconds.",
            "format": "int64",
            "type": "integer"
          },
          "conversation_id": {
            "type": "string"
          },
          "data": true,
          "id": {
            "description": "Increasing; pass the last one back as `cursor`.",
            "format": "int64",
            "type": "integer"
          },
          "prompt_id": {
            "type": "string"
          },
          "type": {
            "type": "string"
          }
        },
        "required": [
          "at",
          "conversation_id",
          "data",
          "id",
          "prompt_id",
          "type"
        ],
        "type": "object"
      },
      "AiCredential": {
        "description": "One account of a provider in a profile. Never the secret.",
        "properties": {
          "active": {
            "description": "The account the proxy uses first for this provider (the first one not resting).",
            "type": "boolean"
          },
          "base_url": {
            "description": "Custom APIs: where the proxy sends the requests.",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "description": "`cred_…`",
            "type": "string"
          },
          "label": {
            "description": "The last characters of the key, e.g. `…7f3a`.",
            "type": "string"
          },
          "limited_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "limited_until": {
            "description": "Hit a rate or usage limit: the proxy skips it until then (unix seconds).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "name": {
            "description": "Custom APIs: the variable name the sandbox gets (e.g. `STRIPE_KEY`).",
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "description": "anthropic, openai, gemini, deepseek, mistral, openrouter, xai, bedrock or custom.",
            "type": "string"
          },
          "secret_header": {
            "description": "Custom APIs: the header the proxy puts the secret in (e.g. `Authorization`), after `secret_prefix`. Absent when it goes in the query string (`secret_query`).",
            "type": [
              "string",
              "null"
            ]
          },
          "secret_prefix": {
            "description": "Custom APIs: what comes before the secret in `secret_header` (e.g. `Bearer `).",
            "type": [
              "string",
              "null"
            ]
          },
          "secret_query": {
            "description": "Custom APIs: the query parameter the proxy puts the secret in, instead of a header.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "active",
          "created_at",
          "id",
          "label",
          "provider"
        ],
        "type": "object"
      },
      "AiProfile": {
        "description": "A credential profile: a named set of AI credentials.",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "credentials": {
            "description": "In switching order per provider.",
            "items": {
              "$ref": "#/components/schemas/AiCredential"
            },
            "type": "array"
          },
          "default": {
            "description": "Sandboxes get the default profile unless their environment or the sandbox names another.",
            "type": "boolean"
          },
          "environments": {
            "description": "Environments whose sandboxes get this profile.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "id": {
            "description": "`aip_…`",
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "credentials",
          "default",
          "environments",
          "id",
          "name"
        ],
        "type": "object"
      },
      "AiProxy": {
        "description": "The account's AI proxy settings (`GET /v1/ai/proxy`).",
        "properties": {
          "blocked": {
            "description": "Every proxied sandbox of the account is refused (403 `ai_blocked`).",
            "type": "boolean"
          },
          "enabled": {
            "description": "On: sandboxes started from now on get placeholder keys and base URLs pointing at the proxy; the real keys stay on froog. Default off.",
            "type": "boolean"
          },
          "url": {
            "description": "The base URL sandboxes send their AI requests to.",
            "type": "string"
          },
          "withhold_subscriptions": {
            "description": "With the proxy on, keep subscription sign-ins (Claude, ChatGPT) out of sandboxes too. They are never proxied. Default false: they pass as without the proxy.",
            "type": "boolean"
          }
        },
        "required": [
          "blocked",
          "enabled",
          "url",
          "withhold_subscriptions"
        ],
        "type": "object"
      },
      "AiSandboxUsage": {
        "description": "Usage of one sandbox in the account view.",
        "properties": {
          "blocked": {
            "type": "boolean"
          },
          "sandbox": {
            "description": "Its name (or its id once deleted).",
            "type": "string"
          },
          "sandbox_id": {
            "type": "string"
          },
          "totals": {
            "$ref": "#/components/schemas/AiTotals"
          }
        },
        "required": [
          "blocked",
          "sandbox",
          "sandbox_id",
          "totals"
        ],
        "type": "object"
      },
      "AiTotals": {
        "description": "Tokens and requests over a period.",
        "properties": {
          "cache_read_tokens": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "cache_write_tokens": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "cost_usd": {
            "description": "Estimated provider cost in USD, from list prices built into froog. Not a froog charge.",
            "format": "double",
            "type": "number"
          },
          "errors": {
            "description": "Answers with status 400 or above (including the proxy's own refusals upstream).",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "input_tokens": {
            "description": "Input tokens not read from a cache.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "output_tokens": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "requests": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "cache_read_tokens",
          "cache_write_tokens",
          "cost_usd",
          "errors",
          "input_tokens",
          "output_tokens",
          "requests"
        ],
        "type": "object"
      },
      "AiUsage": {
        "description": "The account's AI usage (`GET /v1/ai/usage`).",
        "properties": {
          "days": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "sandboxes": {
            "description": "Most expensive first.",
            "items": {
              "$ref": "#/components/schemas/AiSandboxUsage"
            },
            "type": "array"
          },
          "totals": {
            "$ref": "#/components/schemas/AiTotals"
          }
        },
        "required": [
          "days",
          "sandboxes",
          "totals"
        ],
        "type": "object"
      },
      "AiUsageRow": {
        "description": "One row: a UTC day, provider and model.",
        "properties": {
          "cache_read_tokens": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "cache_write_tokens": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "cost_usd": {
            "description": "Estimated provider cost in USD, from list prices built into froog. Not a froog charge.",
            "format": "double",
            "type": "number"
          },
          "day": {
            "description": "YYYY-MM-DD (UTC).",
            "type": "string"
          },
          "errors": {
            "description": "Answers with status 400 or above (including the proxy's own refusals upstream).",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "input_tokens": {
            "description": "Input tokens not read from a cache.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "model": {
            "type": "string"
          },
          "output_tokens": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "provider": {
            "type": "string"
          },
          "requests": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "cache_read_tokens",
          "cache_write_tokens",
          "cost_usd",
          "day",
          "errors",
          "input_tokens",
          "model",
          "output_tokens",
          "provider",
          "requests"
        ],
        "type": "object"
      },
      "AlertSettings": {
        "description": "`GET /v1/account/alerts`: which emails the account gets, and whether an errored sandbox is rebuilt from its last snapshot by itself.",
        "properties": {
          "auto_rebuild": {
            "description": "Rebuild a sandbox whose VM was lost (state `error`) from its last snapshot, and email (default on).",
            "type": "boolean"
          },
          "emails": {
            "items": {
              "$ref": "#/components/schemas/EmailAlert"
            },
            "type": "array"
          }
        },
        "required": [
          "auto_rebuild",
          "emails"
        ],
        "type": "object"
      },
      "ApiKeyInfo": {
        "description": "An API key as listed (the key itself is shown only once, at creation).",
        "properties": {
          "actions": {
            "default": [],
            "description": "What the key may do (`scopes::ACTIONS`); `[\"*\"]` = everything.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "created_by": {
            "description": "An organization key: the email of the member who made it (it acts as that member).",
            "type": [
              "string",
              "null"
            ]
          },
          "environments": {
            "description": "Limited to sandboxes of these environments (names); None = any environment.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "expires_at": {
            "default": null,
            "description": "None = never expires.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "labels": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Limited to sandboxes that have all of these labels; None = any labels.",
            "type": [
              "object",
              "null"
            ]
          },
          "last_used_at": {
            "default": null,
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "preset": {
            "description": "The preset its actions match, if any (read-only, full-sandbox, ci, admin).",
            "type": [
              "string",
              "null"
            ]
          },
          "requests_30d": {
            "default": 0,
            "description": "Requests made with it in the last 30 days.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "sandboxes": {
            "default": null,
            "description": "The sandboxes it may touch (names), besides those it created; None = all.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "sandboxes_created": {
            "default": 0,
            "description": "Sandboxes this key created that still exist.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "created_at",
          "id",
          "label"
        ],
        "type": "object"
      },
      "AuditEvent": {
        "description": "One entry of the account's audit log (`GET /audit`): who changed what, from where. Kept 90 days.",
        "properties": {
          "action": {
            "description": "What happened, e.g. sandbox.create, api_key.revoke, webhook.update, billing.plan.",
            "type": "string"
          },
          "actor": {
            "description": "Who did it: an API key id (`key_…`), `session` (the dashboard), or `public-url` (an auto-start by a visitor of a public URL).",
            "type": "string"
          },
          "actor_label": {
            "description": "The API key's name, or the account email for a dashboard session.",
            "type": [
              "string",
              "null"
            ]
          },
          "at": {
            "description": "Unix seconds.",
            "format": "int64",
            "type": "integer"
          },
          "detail": {
            "description": "Short extra facts, e.g. the sandboxes a create or fork made.",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "description": "`aud_…`",
            "type": "string"
          },
          "ip": {
            "description": "The client's IP address.",
            "type": [
              "string",
              "null"
            ]
          },
          "request_id": {
            "description": "The request's `X-Request-Id`.",
            "type": [
              "string",
              "null"
            ]
          },
          "target": {
            "description": "What it happened to: a sandbox, key, webhook or variable name or id (never a secret).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "action",
          "actor",
          "at",
          "id"
        ],
        "type": "object"
      },
      "AuditList": {
        "properties": {
          "events": {
            "description": "Newest first.",
            "items": {
              "$ref": "#/components/schemas/AuditEvent"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Pass as `cursor` for the next (older) page; None at the end.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "events"
        ],
        "type": "object"
      },
      "AutoTopup": {
        "description": "`PUT /v1/billing/wallet/auto-topup`: charge this much whenever the plan's usage plus the wallet drops below 10% of it (at least $5). 0 turns it off.",
        "properties": {
          "amount_usd": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "amount_usd"
        ],
        "type": "object"
      },
      "Billing": {
        "description": "Payment status of an account (`GET /v1/billing`).",
        "properties": {
          "auto_topup_failures": {
            "default": 0,
            "description": "Declined auto top-ups in a row (3 turn auto top-up off).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "auto_topup_usd": {
            "default": 0,
            "description": "Auto top-up amount in dollars; 0 = off.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "card_on_file": {
            "description": "A payment method is on file.",
            "type": "boolean"
          },
          "enabled": {
            "description": "Payments are set up on this froog server.",
            "type": "boolean"
          },
          "exempt": {
            "description": "The account isn't billed (e.g. the operator's own account).",
            "type": "boolean"
          },
          "extra_starts": {
            "$ref": "#/components/schemas/ExtraStarts",
            "default": {
              "available": false,
              "brackets": [],
              "enabled": false,
              "max_minute_multiple": 0.0
            },
            "description": "Paying from the wallet for starts past the start limits."
          },
          "grace_until": {
            "description": "Out of money: running sandboxes are stopped at this time (unix seconds) unless money is added.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "included_usd": {
            "default": 0.0,
            "description": "This period: what the plan covers, what was used, and what's left (plan plus wallet).",
            "format": "double",
            "type": "number"
          },
          "keep_disks_until": {
            "description": "The plan was canceled with `keep_disks`: once it ends, every sandbox stops, and stopped disks and saved snapshots are kept free until this time (unix seconds).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "max_wallet_per_day_usd": {
            "default": 0,
            "description": "Most the card can be charged for the wallet in 24 hours (payments and auto top-ups).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "min_topup_usd": {
            "default": 0,
            "description": "Smallest wallet payment, dollars.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "plan": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CurrentPlan"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "The account's plan; None until one is chosen."
          },
          "plans": {
            "default": [],
            "description": "The plans on offer, cheapest first.",
            "items": {
              "$ref": "#/components/schemas/PlanInfo"
            },
            "type": "array"
          },
          "rates": {
            "default": [],
            "description": "Per-second rates, quoted per hour and per 730-hour month.",
            "items": {
              "$ref": "#/components/schemas/Rate"
            },
            "type": "array"
          },
          "remaining_usd": {
            "default": 0.0,
            "format": "double",
            "type": "number"
          },
          "suspended": {
            "description": "Out of money: the plan's usage and the wallet ran out and the grace period ended, so sandboxes were stopped. Add money to start them again.",
            "type": "boolean"
          },
          "used_usd": {
            "default": 0.0,
            "format": "double",
            "type": "number"
          },
          "wallet_bonus": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/WalletBonus"
              },
              {
                "type": "null"
              }
            ],
            "description": "The bonus added to wallet payments and auto top-ups by amount; None = no bonus."
          },
          "wallet_usd": {
            "default": 0.0,
            "description": "The wallet: money paid in minus usage past the plan. Negative = owed.",
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "card_on_file",
          "enabled",
          "exempt",
          "suspended"
        ],
        "type": "object"
      },
      "BillingUrl": {
        "description": "A Stripe-hosted page to open in a browser.",
        "properties": {
          "url": {
            "type": "string"
          }
        },
        "required": [
          "url"
        ],
        "type": "object"
      },
      "BrowserRequest": {
        "description": "`POST /sandboxes/{name}/browser`: open the browser view (only Chrome).",
        "properties": {
          "profile": {
            "description": "Chrome's user data directory on the sandbox: an absolute path outside the system directories, created if missing. Default: `~/.config/froog-browser`.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "ChoosePlan": {
        "description": "`POST /v1/billing/plan`: choose or change the plan.",
        "properties": {
          "plan": {
            "description": "Dollars a month: one of `Billing.plans`.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "plan"
        ],
        "type": "object"
      },
      "CiAnalytics": {
        "description": "`GET /v1/ci/analytics?days=&repo=`: what the account's jobs add up to.",
        "properties": {
          "days": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "flaky_tests": {
            "description": "Tests that both failed and passed on the same commit.",
            "items": {
              "$ref": "#/components/schemas/CiFlakyTest"
            },
            "type": "array"
          },
          "jobs": {
            "description": "One row per repository, workflow and job name; most job time first.",
            "items": {
              "$ref": "#/components/schemas/CiJobStats"
            },
            "type": "array"
          },
          "repos": {
            "description": "Most job time first.",
            "items": {
              "$ref": "#/components/schemas/CiRepoStats"
            },
            "type": "array"
          },
          "since": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "days",
          "flaky_tests",
          "jobs",
          "repos",
          "since"
        ],
        "type": "object"
      },
      "CiCache": {
        "properties": {
          "name": {
            "description": "The name in `/cache=<name>`.",
            "type": "string"
          },
          "saved_at": {
            "description": "When the last default-branch job saved it.",
            "format": "int64",
            "type": "integer"
          },
          "size_gb": {
            "description": "What it adds to the base image, in GB.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "snapshot": {
            "description": "Its saved snapshot (`cache-<name>`): `DELETE /v1/saved-snapshots/{snapshot}` starts it over.",
            "type": "string"
          }
        },
        "required": [
          "name",
          "saved_at",
          "snapshot"
        ],
        "type": "object"
      },
      "CiFacet": {
        "properties": {
          "name": {
            "type": "string"
          },
          "runs": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "name",
          "runs"
        ],
        "type": "object"
      },
      "CiFlakyTest": {
        "properties": {
          "commits": {
            "description": "Commits it both failed and passed on.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "failed": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "last_failed_at": {
            "format": "int64",
            "type": "integer"
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "passed": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "repo": {
            "type": "string"
          },
          "suite": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "commits",
          "failed",
          "last_failed_at",
          "name",
          "passed",
          "repo"
        ],
        "type": "object"
      },
      "CiJob": {
        "description": "One GitHub Actions job (`GET /v1/ci`, `GET /v1/ci/jobs/{id}`).",
        "properties": {
          "cache_hit": {
            "description": "With `/cache=`: whether its VM started from the saved cache (false: a cold start).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "conclusion": {
            "description": "GitHub's conclusion once completed: success | failure | cancelled | …",
            "type": [
              "string",
              "null"
            ]
          },
          "cost_usd": {
            "description": "What its job time costs at the CI price (so far, while it runs).",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "finished_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "github_job_id": {
            "description": "GitHub's job id.",
            "format": "int64",
            "type": "integer"
          },
          "head_branch": {
            "description": "The branch the run is for (GitHub's `head_branch`).",
            "type": [
              "string",
              "null"
            ]
          },
          "head_sha": {
            "description": "The commit the run is for.",
            "type": [
              "string",
              "null"
            ]
          },
          "html_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "description": "`ci_…`",
            "type": "string"
          },
          "job_name": {
            "type": "string"
          },
          "labels": {
            "description": "The job's `runs-on` labels.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "queued_at": {
            "format": "int64",
            "type": "integer"
          },
          "reason": {
            "description": "Why it waits, or why it didn't run.",
            "type": [
              "string",
              "null"
            ]
          },
          "repo": {
            "description": "owner/name",
            "type": "string"
          },
          "resources": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CiResources"
              },
              {
                "type": "null"
              }
            ],
            "description": "CPU and memory the job used, once it completed (from the VM's 30-second samples)."
          },
          "run_id": {
            "format": "int64",
            "type": "integer"
          },
          "run_secs": {
            "description": "Seconds the job ran (its billed job time).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "sandbox": {
            "description": "The sandbox that runs it (`ci-<repo>-<job id>`).",
            "type": [
              "string",
              "null"
            ]
          },
          "size": {
            "$ref": "#/components/schemas/Size"
          },
          "started_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "state": {
            "description": "queued (waiting for a sandbox) | starting | running | completed | refused | failed",
            "type": "string"
          },
          "tests": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CiTestSummary"
              },
              {
                "type": "null"
              }
            ],
            "description": "Test results from the JUnit XML files the job wrote, once it completed."
          },
          "wait_secs": {
            "description": "Seconds from queued to the sandbox running.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "workflow": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "github_job_id",
          "id",
          "job_name",
          "labels",
          "queued_at",
          "repo",
          "run_id",
          "size",
          "state"
        ],
        "type": "object"
      },
      "CiJobMetrics": {
        "description": "`GET /v1/ci/jobs/{id}/metrics`: the job's CPU and memory over time, and its steps.",
        "properties": {
          "points": {
            "description": "Averaged into at most 120 buckets, oldest first.",
            "items": {
              "$ref": "#/components/schemas/MetricsPoint"
            },
            "type": "array"
          },
          "resources": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CiResources"
              },
              {
                "type": "null"
              }
            ]
          },
          "steps": {
            "description": "The job's steps, from GitHub, with their times.",
            "items": {
              "$ref": "#/components/schemas/CiStep"
            },
            "type": "array"
          }
        },
        "required": [
          "points",
          "steps"
        ],
        "type": "object"
      },
      "CiJobStats": {
        "properties": {
          "advice": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CiSizeAdvice"
              },
              {
                "type": "null"
              }
            ],
            "description": "A better size for it, when the runs say so."
          },
          "cache_hit_rate": {
            "description": "With `/cache=`: the share of runs that started from the cache (0-1).",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "cancelled": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "cost_usd": {
            "format": "double",
            "type": "number"
          },
          "cpu_avg_percent": {
            "description": "Average of the runs' CPU averages.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "failed": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "failure_rate": {
            "format": "double",
            "type": "number"
          },
          "job_name": {
            "type": "string"
          },
          "memory_peak_percent": {
            "description": "Highest memory any run used, as a share of its VM's.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "minutes": {
            "format": "double",
            "type": "number"
          },
          "oom_runs": {
            "description": "Runs in which the kernel killed a process for want of memory.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "p50_secs": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "p90_secs": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "repo": {
            "type": "string"
          },
          "runs": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "size": {
            "$ref": "#/components/schemas/Size",
            "description": "The size of its latest run."
          },
          "slow_steps": {
            "default": [],
            "description": "Its slowest steps (by p50 over the runs), at most 5.",
            "items": {
              "$ref": "#/components/schemas/CiStepStats"
            },
            "type": "array"
          },
          "succeeded": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "wait_p50_secs": {
            "description": "Queued to running.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "wait_p90_secs": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "workflow": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "cancelled",
          "cost_usd",
          "failed",
          "failure_rate",
          "job_name",
          "minutes",
          "oom_runs",
          "repo",
          "runs",
          "size",
          "succeeded"
        ],
        "type": "object"
      },
      "CiJobTests": {
        "description": "`GET /v1/ci/jobs/{id}/tests`.",
        "properties": {
          "summary": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CiTestSummary"
              },
              {
                "type": "null"
              }
            ],
            "description": "None: the job wrote no JUnit XML froog found."
          },
          "tests": {
            "description": "Failed first, then skipped, then passed; at most 1,000.",
            "items": {
              "$ref": "#/components/schemas/CiTestCase"
            },
            "type": "array"
          }
        },
        "required": [
          "tests"
        ],
        "type": "object"
      },
      "CiLogMatch": {
        "properties": {
          "at": {
            "description": "The line's time, from GitHub's timestamp.",
            "type": [
              "string",
              "null"
            ]
          },
          "branch": {
            "type": [
              "string",
              "null"
            ]
          },
          "conclusion": {
            "type": [
              "string",
              "null"
            ]
          },
          "job_id": {
            "type": "string"
          },
          "job_name": {
            "type": "string"
          },
          "line": {
            "description": "1-based line number in the job's log.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "queued_at": {
            "format": "int64",
            "type": "integer"
          },
          "repo": {
            "type": "string"
          },
          "step": {
            "description": "The step the line is in (from the log's `##[group]` markers).",
            "type": [
              "string",
              "null"
            ]
          },
          "text": {
            "description": "The line without its timestamp (first 500 characters).",
            "type": "string"
          },
          "workflow": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "job_id",
          "job_name",
          "line",
          "queued_at",
          "repo",
          "text"
        ],
        "type": "object"
      },
      "CiLogSearch": {
        "description": "`GET /v1/ci/logs/search?q=&days=&limit=&order=`: lines of the account's kept CI job logs.",
        "properties": {
          "jobs_searched": {
            "description": "Jobs whose logs were searched.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "matches": {
            "description": "Newest job first (`order=oldest`: oldest first, for where a failure first appeared).",
            "items": {
              "$ref": "#/components/schemas/CiLogMatch"
            },
            "type": "array"
          },
          "query": {
            "type": "string"
          },
          "truncated": {
            "description": "More lines matched than `limit`.",
            "type": "boolean"
          }
        },
        "required": [
          "jobs_searched",
          "matches",
          "query",
          "truncated"
        ],
        "type": "object"
      },
      "CiMonitor": {
        "description": "A CI monitor (`GET/POST /v1/ci/monitors`): an alert when matching jobs fail or run long.",
        "properties": {
          "branch": {
            "description": "Only runs for this branch.",
            "type": [
              "string",
              "null"
            ]
          },
          "consecutive": {
            "description": "failure: alert after this many failures in a row (a success starts over).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "cooldown_mins": {
            "description": "No second alert from this monitor for this long.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "duration_secs": {
            "description": "duration: alert when a job has run this long.",
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "email": {
            "description": "Email the account (webhooks listing `ci.monitor.triggered` get it either way).",
            "type": "boolean"
          },
          "id": {
            "description": "`cim_…`",
            "type": "string"
          },
          "job": {
            "description": "Only jobs whose name contains this.",
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "description": "failure (a job failed or timed out) | duration (a job ran longer than `duration_secs`)",
            "type": "string"
          },
          "last_triggered_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "log_pattern": {
            "description": "failure: only failures whose log contains this (any case), e.g. `OutOfMemory` or `SIGKILL`.",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "recent": {
            "default": [],
            "description": "Its last alerts, newest first (at most 10).",
            "items": {
              "$ref": "#/components/schemas/CiMonitorEvent"
            },
            "type": "array"
          },
          "repo": {
            "description": "Only this repository (owner/name).",
            "type": [
              "string",
              "null"
            ]
          },
          "streak": {
            "description": "Failures in a row so far.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "workflow": {
            "description": "Only workflows whose name contains this.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "consecutive",
          "cooldown_mins",
          "created_at",
          "email",
          "id",
          "kind",
          "name",
          "streak"
        ],
        "type": "object"
      },
      "CiMonitorEvent": {
        "properties": {
          "at": {
            "format": "int64",
            "type": "integer"
          },
          "job_id": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        },
        "required": [
          "at",
          "job_id",
          "reason"
        ],
        "type": "object"
      },
      "CiOverview": {
        "description": "`GET /v1/ci`.",
        "properties": {
          "caches": {
            "default": [],
            "description": "The account's caches (`/cache=<name>`: saved snapshots named `cache-<name>`).",
            "items": {
              "$ref": "#/components/schemas/CiCache"
            },
            "type": "array"
          },
          "configured": {
            "description": "This server takes CI jobs (a GitHub App with a webhook secret is set up).",
            "type": "boolean"
          },
          "connected": {
            "description": "The account has a linked installation.",
            "type": "boolean"
          },
          "jobs": {
            "description": "Newest first.",
            "items": {
              "$ref": "#/components/schemas/CiJob"
            },
            "type": "array"
          },
          "label": {
            "description": "`runs-on` label: `<label>-small`, `<label>`, `<label>-large`, `<label>-xlarge` (or `<label>-2vcpu` ... `-16vcpu`), plus `/from=<saved snapshot>`, `/cache=<name>` and `/debug`.",
            "type": "string"
          },
          "period": {
            "$ref": "#/components/schemas/CiPeriod",
            "default": {
              "cost_usd": 0.0,
              "from": 0,
              "minutes": 0.0
            },
            "description": "CI job time in the current billing period."
          },
          "price_per_vcpu_minute": {
            "default": 0.0,
            "description": "The CI price: dollars per vCPU per minute of job time.",
            "format": "double",
            "type": "number"
          },
          "public_repos": {
            "description": "Jobs from public repositories run (off by default).",
            "type": "boolean"
          },
          "public_users": {
            "description": "When public repositories are on: the GitHub users whose runs may use froog (empty = anyone).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "stats": {
            "$ref": "#/components/schemas/CiStats",
            "description": "Last 7 days."
          }
        },
        "required": [
          "configured",
          "connected",
          "jobs",
          "label",
          "public_repos",
          "public_users",
          "stats"
        ],
        "type": "object"
      },
      "CiPeriod": {
        "properties": {
          "cost_usd": {
            "format": "double",
            "type": "number"
          },
          "from": {
            "description": "Start of the billing period.",
            "format": "int64",
            "type": "integer"
          },
          "minutes": {
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "cost_usd",
          "from",
          "minutes"
        ],
        "type": "object"
      },
      "CiRepoStats": {
        "properties": {
          "cost_usd": {
            "format": "double",
            "type": "number"
          },
          "failed": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "failure_rate": {
            "description": "failed / finished runs (0-1).",
            "format": "double",
            "type": "number"
          },
          "minutes": {
            "format": "double",
            "type": "number"
          },
          "repo": {
            "type": "string"
          },
          "runs": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "cost_usd",
          "failed",
          "failure_rate",
          "minutes",
          "repo",
          "runs"
        ],
        "type": "object"
      },
      "CiResources": {
        "description": "What one job used of its VM.",
        "properties": {
          "cpu_avg_percent": {
            "description": "Average share of all vCPUs busy while the job ran.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "cpu_peak_percent": {
            "description": "Busiest 30 seconds.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "memory_peak_mb": {
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "memory_total_mb": {
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "oom_kills": {
            "default": 0,
            "description": "Processes the kernel killed for want of memory during the job.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "type": "object"
      },
      "CiRun": {
        "description": "One GitHub Actions workflow run: the jobs of one run that ran on froog (`GET /v1/ci/runs`, `GET /v1/ci/runs/{run_id}`).",
        "properties": {
          "actor": {
            "description": "The GitHub user who started it.",
            "type": [
              "string",
              "null"
            ]
          },
          "cost_usd": {
            "default": 0.0,
            "description": "What its jobs' time costs.",
            "format": "double",
            "type": "number"
          },
          "duration_secs": {
            "description": "First job started to last job finished (so far, while it runs).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "event": {
            "description": "What started it: push, pull_request, schedule, workflow_dispatch, ...",
            "type": [
              "string",
              "null"
            ]
          },
          "head_branch": {
            "type": [
              "string",
              "null"
            ]
          },
          "head_sha": {
            "type": [
              "string",
              "null"
            ]
          },
          "html_url": {
            "description": "The run on GitHub.",
            "type": [
              "string",
              "null"
            ]
          },
          "jobs": {
            "description": "Its jobs on froog, oldest first.",
            "items": {
              "$ref": "#/components/schemas/CiJob"
            },
            "type": "array"
          },
          "path": {
            "description": "The workflow file, e.g. `.github/workflows/ci.yml`.",
            "type": [
              "string",
              "null"
            ]
          },
          "queued_at": {
            "description": "When its first job was queued.",
            "format": "int64",
            "type": "integer"
          },
          "repo": {
            "description": "owner/name",
            "type": "string"
          },
          "run_id": {
            "description": "GitHub's run id.",
            "format": "int64",
            "type": "integer"
          },
          "run_number": {
            "description": "The run's number in its workflow (`#250`).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "title": {
            "description": "GitHub's title for the run: the head commit's message, or the pull request's title.",
            "type": [
              "string",
              "null"
            ]
          },
          "workflow": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "jobs",
          "queued_at",
          "repo",
          "run_id"
        ],
        "type": "object"
      },
      "CiRunList": {
        "description": "`GET /v1/ci/runs`: one page of runs, newest first, and what the filters can pick from.",
        "properties": {
          "branches": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "repos": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "runs": {
            "items": {
              "$ref": "#/components/schemas/CiRun"
            },
            "type": "array"
          },
          "total": {
            "description": "Runs that match the filters, on every page.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "workflows": {
            "description": "The account's workflows (every run, not only the filtered ones), with their run counts.",
            "items": {
              "$ref": "#/components/schemas/CiFacet"
            },
            "type": "array"
          }
        },
        "required": [
          "branches",
          "repos",
          "runs",
          "total",
          "workflows"
        ],
        "type": "object"
      },
      "CiSettings": {
        "description": "`PUT /v1/ci/settings`.",
        "properties": {
          "public_repos": {
            "type": "boolean"
          },
          "public_users": {
            "default": [],
            "description": "GitHub logins; empty = anyone (only with public_repos).",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "public_repos"
        ],
        "type": "object"
      },
      "CiSizeAdvice": {
        "properties": {
          "kind": {
            "description": "cost | speed | memory",
            "type": "string"
          },
          "label": {
            "description": "The `runs-on` label for it.",
            "type": "string"
          },
          "size": {
            "$ref": "#/components/schemas/Size"
          },
          "why": {
            "type": "string"
          }
        },
        "required": [
          "kind",
          "label",
          "size",
          "why"
        ],
        "type": "object"
      },
      "CiStats": {
        "properties": {
          "failed": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "jobs": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "refused": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "run_secs": {
            "format": "int64",
            "type": "integer"
          },
          "succeeded": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "failed",
          "jobs",
          "refused",
          "run_secs",
          "succeeded"
        ],
        "type": "object"
      },
      "CiStep": {
        "properties": {
          "completed_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "conclusion": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "number": {
            "format": "int64",
            "type": "integer"
          },
          "secs": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "started_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "name",
          "number"
        ],
        "type": "object"
      },
      "CiStepStats": {
        "properties": {
          "name": {
            "type": "string"
          },
          "p50_secs": {
            "format": "int64",
            "type": "integer"
          },
          "p90_secs": {
            "format": "int64",
            "type": "integer"
          },
          "runs": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "name",
          "p50_secs",
          "p90_secs",
          "runs"
        ],
        "type": "object"
      },
      "CiTestCase": {
        "properties": {
          "message": {
            "description": "The failure's message (first 500 characters).",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "secs": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "status": {
            "description": "passed | failed | skipped",
            "type": "string"
          },
          "suite": {
            "description": "The JUnit `classname` (or the suite's name).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "name",
          "status"
        ],
        "type": "object"
      },
      "CiTestSummary": {
        "properties": {
          "failed": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "passed": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "skipped": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "total": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "failed",
          "passed",
          "skipped",
          "total"
        ],
        "type": "object"
      },
      "CliLoginInfo": {
        "description": "`GET /cli-login/{code}`: what's being approved.",
        "properties": {
          "code": {
            "type": "string"
          },
          "device": {
            "type": "string"
          },
          "expires_at": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "code",
          "device",
          "expires_at"
        ],
        "type": "object"
      },
      "CliLoginPoll": {
        "description": "`POST /cli-login/poll`",
        "properties": {
          "poll_token": {
            "type": "string"
          }
        },
        "required": [
          "poll_token"
        ],
        "type": "object"
      },
      "CliLoginRequest": {
        "description": "`POST /cli-login` (no auth): start an `froog login` in the browser.",
        "properties": {
          "device": {
            "default": "",
            "description": "Shown on the approval page, e.g. the computer's hostname.",
            "type": "string"
          }
        },
        "type": "object"
      },
      "CliLoginResult": {
        "properties": {
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "key": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "description": "\"pending\" or \"approved\"",
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "type": "object"
      },
      "CliLoginStarted": {
        "properties": {
          "code": {
            "description": "Show this; the dashboard asks the person to check it matches.",
            "type": "string"
          },
          "expires_in": {
            "format": "int64",
            "type": "integer"
          },
          "poll_token": {
            "description": "Secret: poll with it. Never show it.",
            "type": "string"
          },
          "url": {
            "description": "Open this in the browser.",
            "type": "string"
          }
        },
        "required": [
          "code",
          "expires_in",
          "poll_token",
          "url"
        ],
        "type": "object"
      },
      "CommandList": {
        "properties": {
          "commands": {
            "items": {
              "$ref": "#/components/schemas/CommandRecord"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Pass as `cursor` for the next (older) page; None at the end.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "commands"
        ],
        "type": "object"
      },
      "CommandLogs": {
        "description": "A chunk of a command's stored output from `offset`. Read again from `next_offset` until `done` (the command ended and everything was read).",
        "properties": {
          "data": {
            "description": "UTF-8 text, or base64 with `encoding=base64`.",
            "type": "string"
          },
          "done": {
            "type": "boolean"
          },
          "next_offset": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "offset": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "size": {
            "description": "Bytes stored so far for this stream.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "data",
          "done",
          "next_offset",
          "offset",
          "size",
          "status"
        ],
        "type": "object"
      },
      "CommandRecord": {
        "description": "One command in a sandbox's history (`GET /sandboxes/{name}/command-history`). Kept 90 days, readable while the sandbox is stopped. `mode`: sync | stream | detached. `status`: running | paused (frozen with a sandbox stopped with its memory kept; a start resumes it) | exited | timed_out | failed | killed | lost.",
        "properties": {
          "command": {
            "description": "The command text (first 64 KiB).",
            "type": "string"
          },
          "ended_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "exit_code": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "job_id": {
            "description": "The background job behind a stream/detached command (`froog logs`, `froog kill`).",
            "type": [
              "string",
              "null"
            ]
          },
          "mode": {
            "type": "string"
          },
          "oom_killed": {
            "default": false,
            "description": "The kernel killed it for using too much memory (exit code 137).",
            "type": "boolean"
          },
          "output_truncated": {
            "description": "Output past the per-command or per-account cap was dropped.",
            "type": "boolean"
          },
          "started_at": {
            "format": "int64",
            "type": "integer"
          },
          "status": {
            "type": "string"
          },
          "stderr_size": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "stdout_size": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "command",
          "id",
          "mode",
          "output_truncated",
          "started_at",
          "status",
          "stderr_size",
          "stdout_size"
        ],
        "type": "object"
      },
      "Connection": {
        "description": "One way to sign in to the account (`GET /v1/account/connections`).",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "email": {
            "description": "The address this connection signs in with (GitHub: the account's verified primary address).",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "description": "`con_…`",
            "type": "string"
          },
          "login": {
            "description": "The GitHub login, for a GitHub connection.",
            "type": [
              "string",
              "null"
            ]
          },
          "primary": {
            "description": "Its address gets the account's emails (the account's email).",
            "type": "boolean"
          },
          "provider": {
            "description": "google | github | email | agentid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "id",
          "primary",
          "provider"
        ],
        "type": "object"
      },
      "Conversation": {
        "description": "A conversation: a thread of prompts with the agent's memory (the harness's own session).",
        "properties": {
          "agent": {
            "description": "The harness of its last prompt.",
            "type": "string"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "current": {
            "description": "The one a prompt without `conversation_id` or `new` continues (the most recent).",
            "type": "boolean"
          },
          "id": {
            "type": "string"
          },
          "last_prompt": {
            "description": "The start of its last prompt.",
            "type": "string"
          },
          "model": {
            "type": [
              "string",
              "null"
            ]
          },
          "prompts": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "queued": {
            "description": "Prompts waiting for their turn.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "running": {
            "description": "A turn is running in it now.",
            "type": "boolean"
          },
          "sandbox": {
            "type": "string"
          },
          "updated_at": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "agent",
          "created_at",
          "current",
          "id",
          "last_prompt",
          "prompts",
          "queued",
          "running",
          "sandbox",
          "updated_at"
        ],
        "type": "object"
      },
      "ConversationDetail": {
        "description": "A conversation with its prompts, oldest first.",
        "properties": {
          "agent": {
            "description": "The harness of its last prompt.",
            "type": "string"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "current": {
            "description": "The one a prompt without `conversation_id` or `new` continues (the most recent).",
            "type": "boolean"
          },
          "id": {
            "type": "string"
          },
          "last_prompt": {
            "description": "The start of its last prompt.",
            "type": "string"
          },
          "model": {
            "type": [
              "string",
              "null"
            ]
          },
          "prompts": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "queued": {
            "description": "Prompts waiting for their turn.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "running": {
            "description": "A turn is running in it now.",
            "type": "boolean"
          },
          "sandbox": {
            "type": "string"
          },
          "turns": {
            "items": {
              "$ref": "#/components/schemas/Prompt"
            },
            "type": "array"
          },
          "updated_at": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "agent",
          "created_at",
          "current",
          "id",
          "last_prompt",
          "prompts",
          "queued",
          "running",
          "sandbox",
          "turns",
          "updated_at"
        ],
        "type": "object"
      },
      "ConversationList": {
        "properties": {
          "conversations": {
            "items": {
              "$ref": "#/components/schemas/Conversation"
            },
            "type": "array"
          }
        },
        "required": [
          "conversations"
        ],
        "type": "object"
      },
      "CreateAiProfile": {
        "properties": {
          "copy_from": {
            "description": "Start with a copy of this profile's credentials.",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "description": "1-40 of a-z, 0-9 and -.",
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "CreateCiMonitor": {
        "description": "`POST /v1/ci/monitors`.",
        "properties": {
          "branch": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          },
          "consecutive": {
            "default": null,
            "description": "1-20, default 1.",
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "cooldown_mins": {
            "default": null,
            "description": "0-1440, default 60.",
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "duration_secs": {
            "default": null,
            "description": "Required for duration: 60 to 21600.",
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "email": {
            "default": null,
            "description": "Default true.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "job": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "default": null,
            "description": "failure (default) | duration",
            "type": [
              "string",
              "null"
            ]
          },
          "log_pattern": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "repo": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          },
          "workflow": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "CreateInbox": {
        "properties": {
          "name": {
            "description": "Your label for it.",
            "type": [
              "string",
              "null"
            ]
          },
          "sandbox": {
            "description": "Attach it to this sandbox: it's `FROOG_EMAIL` there (from the sandbox's next start), and the key inside the sandbox can read it. The address starts with the sandbox's name unless `username` says otherwise.",
            "type": [
              "string",
              "null"
            ]
          },
          "username": {
            "description": "The start of the address (letters, digits, dots, dashes; 1 to 32). froog adds a random suffix: `signup` becomes `signup-k3f9qz@froogmail.com`. Default: `agent`.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "CreateSandbox": {
        "properties": {
          "auto_start": {
            "description": "true: while stopped, a request to one of its public URLs, or an exec, file, job or wait call, starts it. Default false.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "count": {
            "description": "Create `count` sandboxes named `name-1..name-N`.",
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "delete_after_secs": {
            "description": "Delete it after it has stayed stopped this many seconds (0 or absent = never; at most 365 days). A start before then cancels the countdown.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "env": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Its own environment variables (on top of the account's; they win, and apply even with `environment: false`). With `from`, the default is the saved snapshot's source's.",
            "type": [
              "object",
              "null"
            ]
          },
          "environment": {
            "description": "false: start with none of the account's environment (no env vars, repos, files or setup script), e.g. for code or people you don't trust with your credentials. Default true, except from a share code (`from: \"fsh_…\"`) or the saved copy one gave: false there (another account prepared that disk); `true` opts in.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "environment_name": {
            "description": "The environment it uses (`GET /environments`), at its latest version. Default: the account's default environment. Kept with `environment: false` (it then gets none of it).",
            "type": [
              "string",
              "null"
            ]
          },
          "expires_in_secs": {
            "description": "Delete it this many seconds after it's created, running or not (60 s to 365 days; absent = never). Shows as `expires_at`.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "files": {
            "description": "Files written into the home directory before the sandbox counts as running (first boot only; mode 600; at most 20, 1 MiB together).",
            "items": {
              "$ref": "#/components/schemas/NewFile"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "from": {
            "description": "Start from this saved snapshot (its name): its disk, OS and, unless `size` is given, size. Or a share code (`fsh_…`) another account gave you: a copy of its saved snapshot becomes a saved snapshot of yours, and the owner's logins, keys and secret files are removed from the disk before the sandbox counts as running.",
            "type": [
              "string",
              "null"
            ]
          },
          "labels": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Key-value tags (at most 32; keys 1-63 of `a-z A-Z 0-9 . _ - /`, values up to 255 characters).",
            "type": [
              "object",
              "null"
            ]
          },
          "max_lifetime_secs": {
            "description": "Stop it this many seconds after each start, busy or not, even while an agent prompt runs (0 or absent = no limit; at most 30 days). The auto-stop timer (`ttl_secs`) still applies.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "monitoring": {
            "description": "false: keep no command history or process samples. Default: the account's setting.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "os": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Os"
              },
              {
                "type": "null"
              }
            ],
            "description": "Operating system; default Ubuntu 24.04."
          },
          "repo": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SandboxRepo"
              },
              {
                "type": "null"
              }
            ],
            "description": "A git repo cloned into this sandbox only, by the setup job at boot (also with `environment: false`)."
          },
          "setup": {
            "description": "A script run once, in the background, after the first boot (as job \"setup\").",
            "type": [
              "string",
              "null"
            ]
          },
          "size": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Size"
              },
              {
                "type": "null"
              }
            ]
          },
          "snapshots": {
            "description": "false: never snapshot it; a stop erases it. Default: the account's setting.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "ttl_secs": {
            "description": "Auto-stop this many seconds after each start, busy or not (at most 30 days; 0 = no auto-stop). Absent or null: 1 hour (2 hours during the free trial, which needs one).",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "visibility": {
            "description": "In an organization: `shared` (every member can use it) or `private` (only you). Default: the organization's default visibility. A personal sandbox is always private.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "CreateSnapshot": {
        "properties": {
          "label": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "CreatedApiKey": {
        "properties": {
          "actions": {
            "default": [],
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "environments": {
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "expires_at": {
            "default": null,
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "key": {
            "description": "Shown once; store it now.",
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "labels": {
            "additionalProperties": {
              "type": "string"
            },
            "type": [
              "object",
              "null"
            ]
          },
          "sandboxes": {
            "default": null,
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "key",
          "label"
        ],
        "type": "object"
      },
      "CreatedSnapshotShare": {
        "description": "`POST /saved-snapshots/{name}/shares`: the code, once.",
        "properties": {
          "code": {
            "description": "`fsh_…`: another account runs `froog new --from fsh_…`. Shown once; froog keeps only a hash.",
            "type": "string"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "created_at",
          "id",
          "name"
        ],
        "type": "object"
      },
      "CurrentPlan": {
        "description": "The account's plan, mirrored from its Stripe subscription.",
        "properties": {
          "cancel_at_period_end": {
            "description": "Canceled: the plan ends with the period.",
            "type": "boolean"
          },
          "max_sandboxes": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "period_end": {
            "format": "int64",
            "type": "integer"
          },
          "period_start": {
            "description": "The current billing period (or the trial), unix seconds.",
            "format": "int64",
            "type": "integer"
          },
          "saved_snapshots": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "status": {
            "description": "trialing | active | past_due | unpaid | canceled | incomplete",
            "type": "string"
          },
          "trial_ends_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "usd": {
            "description": "Dollars a month.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "cancel_at_period_end",
          "max_sandboxes",
          "period_end",
          "period_start",
          "saved_snapshots",
          "status",
          "usd"
        ],
        "type": "object"
      },
      "DashboardLink": {
        "description": "`POST /v1/dashboard-link`: open the dashboard signed in. The code in the URL works once and expires at `expires_at`; it can't call the API.",
        "properties": {
          "expires_at": {
            "format": "int64",
            "type": "integer"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "expires_at",
          "url"
        ],
        "type": "object"
      },
      "DataRetention": {
        "description": "`GET/PATCH /account/data-retention`. Changing it needs a dashboard session, not an API key.",
        "properties": {
          "deletion_operation": {
            "description": "Turning zero data retention on just now started erasing: this deletion operation (`GET /deletion-operations/{id}`) follows it. Only in the answer to that change.",
            "type": [
              "string",
              "null"
            ]
          },
          "monitoring_off": {
            "description": "New sandboxes keep no command history or process samples.",
            "type": "boolean"
          },
          "snapshots_off": {
            "description": "New sandboxes are never snapshotted (a stop erases them).",
            "type": "boolean"
          },
          "zero_data_retention": {
            "description": "Erase each sandbox's data (disk, snapshots, history) when it stops; no saved snapshots.",
            "type": "boolean"
          }
        },
        "required": [
          "monitoring_off",
          "snapshots_off",
          "zero_data_retention"
        ],
        "type": "object"
      },
      "DeletedSnapshots": {
        "description": "`DELETE /sandboxes/{name}/snapshots`: the automatic snapshots that were deleted.",
        "properties": {
          "deleted": {
            "description": "Their ids.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "kept": {
            "description": "The snapshot a stopped (or errored) sandbox will start from, which is kept.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "deleted"
        ],
        "type": "object"
      },
      "DeletionOperation": {
        "description": "A deletion that runs in the background: closing an account (erased after the 30-day reopen window) or turning on zero data retention. `GET /v1/deletion-operations/{id}`.",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "error": {
            "description": "Why the last attempt couldn't finish (status blocked).",
            "type": [
              "string",
              "null"
            ]
          },
          "expected_by": {
            "description": "When the erasure is due (an account close: the end of the reopen window).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "description": "`dop_…`",
            "type": "string"
          },
          "kind": {
            "description": "account_close | zero_data_retention",
            "type": "string"
          },
          "stage": {
            "description": "waiting_for_reopen_window | removing | retrying | completed | reopened",
            "type": "string"
          },
          "status": {
            "description": "pending | processing | blocked | completed | canceled. `blocked` is not final: it is retried.",
            "type": "string"
          },
          "updated_at": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "created_at",
          "id",
          "kind",
          "stage",
          "status",
          "updated_at"
        ],
        "type": "object"
      },
      "DesktopLink": {
        "description": "`POST /sandboxes/{name}/desktop`: a link to the VM's desktop in the browser.",
        "properties": {
          "expires_at": {
            "format": "int64",
            "type": "integer"
          },
          "url": {
            "description": "Secret: carries a token (in the fragment, after `#`). Open it within 10 minutes; an open session keeps working. Add `overlay=0` to the query (before the `#`) to hide the viewer's controls and stats, e.g. in an iframe.",
            "type": "string"
          }
        },
        "required": [
          "expires_at",
          "url"
        ],
        "type": "object"
      },
      "EmailAlert": {
        "properties": {
          "description": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "kind": {
            "description": "disk | stop_refused | unresponsive | rebuilt | plan_nudge | billing",
            "type": "string"
          }
        },
        "required": [
          "description",
          "enabled",
          "kind"
        ],
        "type": "object"
      },
      "EmailCodeRequest": {
        "description": "`POST /v1/account/connections/email`: send a 6-digit code to an address to connect it.",
        "properties": {
          "email": {
            "type": "string"
          }
        },
        "required": [
          "email"
        ],
        "type": "object"
      },
      "EmailCodeVerify": {
        "description": "`POST /v1/account/connections/email/verify`: the code from the email.",
        "properties": {
          "code": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "email"
        ],
        "type": "object"
      },
      "EnvFile": {
        "description": "A secret file written into every sandbox at each start (content never returned).",
        "properties": {
          "path": {
            "description": "Relative to the home directory, e.g. `.npmrc` or `app/.env`.",
            "type": "string"
          },
          "size": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "updated_at": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "path",
          "size",
          "updated_at"
        ],
        "type": "object"
      },
      "EnvVar": {
        "description": "An account environment variable as listed (the value is never returned, only a preview).",
        "properties": {
          "name": {
            "type": "string"
          },
          "preview": {
            "description": "e.g. \"sk-a…9xQ\"; the whole value if it's short and not secret-looking.",
            "type": "string"
          },
          "updated_at": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "name",
          "preview",
          "updated_at"
        ],
        "type": "object"
      },
      "Environment": {
        "description": "The account's environment: what every new sandbox starts with, besides env vars.",
        "properties": {
          "default": {
            "default": false,
            "description": "New sandboxes use it when they name no environment.",
            "type": "boolean"
          },
          "files": {
            "items": {
              "$ref": "#/components/schemas/EnvFile"
            },
            "type": "array"
          },
          "name": {
            "default": "",
            "description": "Its name (`default` for the account's first one).",
            "type": "string"
          },
          "repo_setup": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "A setup script per repo (by its directory under ~), run in that directory after cloning, at every start, before the environment's own setup script.",
            "type": "object"
          },
          "repos": {
            "description": "Git URLs cloned into `~/<repo>` when the directory doesn't exist yet (`https://github.com/org/repo`, optionally `#branch`).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "setup": {
            "description": "Shell script run in the background at every start, after cloning (as job \"setup\").",
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "format": "int64",
            "type": "integer"
          },
          "version": {
            "default": 0,
            "description": "Its latest version: every change makes a new one. Sandboxes stay on the version they started with until `POST /environments/{env}/upgrade`.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "files",
          "repos",
          "updated_at"
        ],
        "type": "object"
      },
      "EnvironmentSummary": {
        "description": "One environment in `GET /environments`.",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "default": {
            "description": "New sandboxes use it when they name none.",
            "type": "boolean"
          },
          "files": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "repos": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "sandboxes": {
            "description": "Sandboxes (not deleted) per version they are on, newest version first.",
            "items": {
              "$ref": "#/components/schemas/EnvironmentVersionUse"
            },
            "type": "array"
          },
          "setup": {
            "description": "It has a setup script.",
            "type": "boolean"
          },
          "updated_at": {
            "format": "int64",
            "type": "integer"
          },
          "version": {
            "description": "Its latest version (every change makes a new one).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "created_at",
          "default",
          "files",
          "name",
          "repos",
          "sandboxes",
          "setup",
          "updated_at",
          "version"
        ],
        "type": "object"
      },
      "EnvironmentUpgrade": {
        "description": "The answer to `POST /environments/{env}/upgrade`.",
        "properties": {
          "applied": {
            "description": "Running sandboxes that got the new version now (secret files written, files the new version dropped removed, the setup job started again).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "at_next_start": {
            "description": "Sandboxes that get it at their next start (stopped, or not reachable right now).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "environment": {
            "type": "string"
          },
          "version": {
            "description": "The version they are on now.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "applied",
          "at_next_start",
          "environment",
          "version"
        ],
        "type": "object"
      },
      "EnvironmentVersion": {
        "description": "One version of an environment (`GET /environments/{env}/versions`).",
        "properties": {
          "change": {
            "description": "What the change was, e.g. \"repos\", \"setup script\", \"file .npmrc set\".",
            "type": "string"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "sandboxes": {
            "description": "Sandboxes (not deleted) on this version.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "version": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "change",
          "created_at",
          "sandboxes",
          "version"
        ],
        "type": "object"
      },
      "EnvironmentVersionUse": {
        "properties": {
          "sandboxes": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "version": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "sandboxes",
          "version"
        ],
        "type": "object"
      },
      "ErrorBody": {
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorDetail"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "ErrorDetail": {
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "request_id": {
            "description": "This request's id (also in the `X-Request-Id` header); quote it when reporting a problem.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "code",
          "message"
        ],
        "type": "object"
      },
      "EventList": {
        "properties": {
          "events": {
            "items": {
              "$ref": "#/components/schemas/AgentEvent"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "The id of the last event: pass it as `cursor` to get only newer ones.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "events",
          "next_cursor"
        ],
        "type": "object"
      },
      "ExecEvent": {
        "description": "One line of a streamed exec (`stream: true`): `started` first, then `stdout`/`stderr` chunks as they arrive, then exactly one `exit` or `error`.",
        "oneOf": [
          {
            "properties": {
              "command_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "type": {
                "enum": [
                  "started"
                ],
                "type": "string"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          },
          {
            "description": "A UTF-8 chunk of output (invalid bytes become U+FFFD).",
            "properties": {
              "data": {
                "type": "string"
              },
              "type": {
                "enum": [
                  "stdout"
                ],
                "type": "string"
              }
            },
            "required": [
              "data",
              "type"
            ],
            "type": "object"
          },
          {
            "properties": {
              "data": {
                "type": "string"
              },
              "type": {
                "enum": [
                  "stderr"
                ],
                "type": "string"
              }
            },
            "required": [
              "data",
              "type"
            ],
            "type": "object"
          },
          {
            "description": "124 when it timed out. `oom_killed`: the kernel killed it for using too much memory.",
            "properties": {
              "exit_code": {
                "format": "int32",
                "type": "integer"
              },
              "oom_killed": {
                "type": "boolean"
              },
              "timed_out": {
                "type": "boolean"
              },
              "type": {
                "enum": [
                  "exit"
                ],
                "type": "string"
              }
            },
            "required": [
              "exit_code",
              "timed_out",
              "type"
            ],
            "type": "object"
          },
          {
            "description": "The command couldn't finish: the connection to the sandbox broke, or froog failed.",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "type": {
                "enum": [
                  "error"
                ],
                "type": "string"
              }
            },
            "required": [
              "code",
              "message",
              "type"
            ],
            "type": "object"
          }
        ]
      },
      "ExecRequest": {
        "properties": {
          "command": {
            "type": "string"
          },
          "cwd": {
            "description": "Run in this directory (relative to the home directory, or absolute).",
            "type": [
              "string",
              "null"
            ]
          },
          "env": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Extra environment variables for this command only.",
            "type": [
              "object",
              "null"
            ]
          },
          "stdin": {
            "description": "Text fed to the command's standard input, which then ends (at most 1 MiB). Without it (and `stdin_b64`), stdin is empty.",
            "type": [
              "string",
              "null"
            ]
          },
          "stdin_b64": {
            "description": "Like `stdin`, base64-encoded (for binary input; at most 1 MiB decoded).",
            "type": [
              "string",
              "null"
            ]
          },
          "stream": {
            "description": "true: answer with `application/x-ndjson`, one `ExecEvent` per line as output arrives (also chosen by `Accept: application/x-ndjson`).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "timeout_secs": {
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "command"
        ],
        "type": "object"
      },
      "ExecResult": {
        "properties": {
          "command_id": {
            "description": "The command's record in the history (`GET /sandboxes/{name}/command-history/{id}`).",
            "type": [
              "string",
              "null"
            ]
          },
          "exit_code": {
            "description": "124 when it timed out.",
            "format": "int32",
            "type": "integer"
          },
          "oom_killed": {
            "default": false,
            "description": "The kernel killed it for using too much memory (exit code 137 and an out-of-memory kill in the kernel log while it ran).",
            "type": "boolean"
          },
          "stderr": {
            "type": "string"
          },
          "stdout": {
            "type": "string"
          },
          "timed_out": {
            "default": false,
            "description": "It ran past `timeout_secs` and was killed; stdout and stderr hold what it printed until then.",
            "type": "boolean"
          }
        },
        "required": [
          "exit_code",
          "stderr",
          "stdout"
        ],
        "type": "object"
      },
      "ExtraStarts": {
        "description": "Starts past the start limits (per minute, hour, day), paid from the wallet. Off by default.",
        "properties": {
          "available": {
            "description": "They can run now: on, with a paid plan (not the trial or a plan set to end) and money in the wallet.",
            "type": "boolean"
          },
          "brackets": {
            "description": "The price of a start by how far past the included number it is. A start pays the highest price of the minute, hour and day windows.",
            "items": {
              "$ref": "#/components/schemas/StartBracket"
            },
            "type": "array"
          },
          "enabled": {
            "description": "Turned on for this account (`PUT /billing/extra-starts`).",
            "type": "boolean"
          },
          "max_minute_multiple": {
            "description": "Past this multiple of the per-minute limit, a start fails even when paid.",
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "available",
          "brackets",
          "enabled",
          "max_minute_multiple"
        ],
        "type": "object"
      },
      "Feedback": {
        "description": "`POST /feedback`: a message to the froog team (replies go to the account email).",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": [
          "message"
        ],
        "type": "object"
      },
      "FileEntry": {
        "description": "One entry of a directory listing. `kind`: file | dir | link | other.",
        "properties": {
          "kind": {
            "type": "string"
          },
          "modified": {
            "format": "int64",
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "size": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "kind",
          "modified",
          "name",
          "size"
        ],
        "type": "object"
      },
      "FileEvent": {
        "description": "One line of `GET /sandboxes/{name}/files/watch` (NDJSON). `type`: `ready` (watching; `method` inotify or poll), `change` (`event` create | modify | delete, `path`, `dir`), `error` (`message`), and last `end` (`reason` timeout | exited | error).",
        "properties": {
          "dir": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "event": {
            "type": [
              "string",
              "null"
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "method": {
            "type": [
              "string",
              "null"
            ]
          },
          "path": {
            "description": "As inotify or find print it: absolute if the watched path was, else relative to ~.",
            "type": [
              "string",
              "null"
            ]
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string"
          }
        },
        "required": [
          "type"
        ],
        "type": "object"
      },
      "FileFind": {
        "description": "`GET /sandboxes/{name}/files/find?path=&pattern=&regex=`: lines that contain a text.",
        "properties": {
          "errors": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "matches": {
            "description": "At most 1,000.",
            "items": {
              "$ref": "#/components/schemas/FileMatch"
            },
            "type": "array"
          },
          "truncated": {
            "type": "boolean"
          }
        },
        "required": [
          "matches",
          "truncated"
        ],
        "type": "object"
      },
      "FileInfo": {
        "description": "`GET /sandboxes/{name}/files?path=`: a file's details, or a directory and its entries.",
        "properties": {
          "entries": {
            "items": {
              "$ref": "#/components/schemas/FileEntry"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "kind": {
            "type": "string"
          },
          "modified": {
            "format": "int64",
            "type": "integer"
          },
          "path": {
            "type": "string"
          },
          "size": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "kind",
          "modified",
          "path",
          "size"
        ],
        "type": "object"
      },
      "FileMatch": {
        "properties": {
          "content": {
            "description": "The line, cut at 500 characters.",
            "type": "string"
          },
          "file": {
            "type": "string"
          },
          "line": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "content",
          "file",
          "line"
        ],
        "type": "object"
      },
      "FilePermissions": {
        "description": "`POST /sandboxes/{name}/files/permissions`: chmod. The owner (the sandbox user) stays.",
        "properties": {
          "mode": {
            "description": "Octal, e.g. 755 or 0600.",
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "recursive": {
            "default": false,
            "description": "Also everything inside a directory.",
            "type": "boolean"
          }
        },
        "required": [
          "mode",
          "path"
        ],
        "type": "object"
      },
      "FileReplace": {
        "description": "`POST /sandboxes/{name}/files/replace`: replace every occurrence of `pattern` (plain text, byte for byte) with `new_value` in each file (up to 100 files, 5 MiB each).",
        "properties": {
          "new_value": {
            "type": "string"
          },
          "paths": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "pattern": {
            "type": "string"
          }
        },
        "required": [
          "new_value",
          "paths",
          "pattern"
        ],
        "type": "object"
      },
      "FileReplaced": {
        "properties": {
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "file": {
            "type": "string"
          },
          "replacements": {
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "success": {
            "type": "boolean"
          }
        },
        "required": [
          "file",
          "success"
        ],
        "type": "object"
      },
      "FileSearch": {
        "description": "`GET /sandboxes/{name}/files/search?path=&pattern=`: paths whose name matches a glob.",
        "properties": {
          "errors": {
            "description": "Parts of the tree that couldn't be searched (the results are then incomplete).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "files": {
            "description": "Absolute paths, at most 10,000.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "truncated": {
            "type": "boolean"
          }
        },
        "required": [
          "files",
          "truncated"
        ],
        "type": "object"
      },
      "FileUrl": {
        "description": "A URL that GETs (download) or PUTs (upload, raw bytes) one file with no Authorization header.",
        "properties": {
          "expires_at": {
            "format": "int64",
            "type": "integer"
          },
          "method": {
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "expires_at",
          "method",
          "url"
        ],
        "type": "object"
      },
      "ForkSandbox": {
        "properties": {
          "count": {
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "env": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Environment variables set on top of the source's own (these win).",
            "type": [
              "object",
              "null"
            ]
          },
          "environment": {
            "description": "false: the copies run without the environment; when the source had it, the owner's logins, keys and secret files are removed from their disks before they count as running. Default: the source's.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "environment_name": {
            "description": "Move the copies to this environment's latest version. Default: exactly the source's environment and version.",
            "type": [
              "string",
              "null"
            ]
          },
          "labels": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Labels set on top of the source's own (these win).",
            "type": [
              "object",
              "null"
            ]
          },
          "monitoring": {
            "description": "Override the source's monitoring setting.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "size": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Size"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Size of the new sandboxes; defaults to the source's."
          },
          "snapshot": {
            "description": "Snapshot id or label. Defaults to a fresh snapshot (running) or the latest one (stopped).",
            "type": [
              "string",
              "null"
            ]
          },
          "snapshots": {
            "description": "false: never snapshot the copies; a stop erases them. Default: the account's setting.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "ttl_secs": {
            "description": "Auto-stop timer of the copies in seconds (0 = no auto-stop). Default: the source's.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "GithubConnect": {
        "description": "`POST /v1/github/connect`: where to install the app (or pick another account).",
        "properties": {
          "url": {
            "type": "string"
          }
        },
        "required": [
          "url"
        ],
        "type": "object"
      },
      "GithubInstallation": {
        "description": "A GitHub App installation linked to the account.",
        "properties": {
          "account": {
            "description": "The GitHub user or organization it is installed on.",
            "type": "string"
          },
          "account_type": {
            "description": "User | Organization",
            "type": "string"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "description": "GitHub's installation id.",
            "format": "int64",
            "type": "integer"
          },
          "repository_selection": {
            "description": "all | selected (the repositories GitHub lets the app see)",
            "type": "string"
          }
        },
        "required": [
          "account",
          "account_type",
          "created_at",
          "id",
          "repository_selection"
        ],
        "type": "object"
      },
      "GithubRepo": {
        "description": "A repository the app can see (`GET /v1/github/repos`).",
        "properties": {
          "clone_url": {
            "description": "https://github.com/owner/name.git",
            "type": "string"
          },
          "default_branch": {
            "type": [
              "string",
              "null"
            ]
          },
          "full_name": {
            "description": "owner/name",
            "type": "string"
          },
          "id": {
            "format": "int64",
            "type": "integer"
          },
          "installation_id": {
            "format": "int64",
            "type": "integer"
          },
          "private": {
            "type": "boolean"
          }
        },
        "required": [
          "clone_url",
          "full_name",
          "id",
          "installation_id",
          "private"
        ],
        "type": "object"
      },
      "GithubStatus": {
        "description": "`GET /v1/github`.",
        "properties": {
          "ci_label": {
            "description": "The `runs-on` label of CI jobs that run on froog.",
            "type": "string"
          },
          "configured": {
            "description": "This server has a GitHub App set up (otherwise every other GitHub call is 404 github_not_configured).",
            "type": "boolean"
          },
          "installations": {
            "items": {
              "$ref": "#/components/schemas/GithubInstallation"
            },
            "type": "array"
          },
          "token_repos": {
            "description": "`owner/name` of the repositories the token in each sandbox may use; empty = every repository the app can see.",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "ci_label",
          "configured",
          "installations",
          "token_repos"
        ],
        "type": "object"
      },
      "GithubToken": {
        "description": "A short-lived GitHub installation token (one hour).",
        "properties": {
          "expires_at": {
            "format": "int64",
            "type": "integer"
          },
          "owner": {
            "description": "The GitHub account it works for.",
            "type": "string"
          },
          "repositories": {
            "description": "The repositories it is limited to; empty = every repository of the installation.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "token": {
            "type": "string"
          }
        },
        "required": [
          "expires_at",
          "owner",
          "repositories",
          "token"
        ],
        "type": "object"
      },
      "GithubTokenRequest": {
        "description": "`POST /v1/sandboxes/{name}/github-token`.",
        "properties": {
          "owner": {
            "description": "The GitHub user or organization (default: the first linked installation).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "Inbox": {
        "description": "An email address that receives mail for an agent (`/v1/inboxes`). Receive-only for now.",
        "properties": {
          "address": {
            "description": "The full address, e.g. `signup-k3f9qz@froogmail.com`.",
            "type": "string"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "type": "string"
          },
          "last_message_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "messages": {
            "default": 0,
            "description": "Messages kept (older than the retention period are deleted).",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "name": {
            "default": "",
            "description": "Your label for it (not part of the address).",
            "type": "string"
          },
          "sandbox": {
            "description": "The sandbox it belongs to, if any.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "address",
          "created_at",
          "id"
        ],
        "type": "object"
      },
      "InboxBilling": {
        "description": "What the account pays for inboxes (`GET /v1/inboxes/billing`).",
        "properties": {
          "active": {
            "description": "Whether inboxes can be made and receive mail now.",
            "type": "boolean"
          },
          "cancel_at_period_end": {
            "default": false,
            "type": "boolean"
          },
          "period_end": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "price_cents": {
            "description": "One inbox a month, in US cents.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "required": {
            "description": "Whether this account pays for inboxes (false: billing-exempt, or a server without payments).",
            "type": "boolean"
          },
          "seats": {
            "description": "Inboxes paid for this period.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "status": {
            "description": "The Stripe subscription's status (active, past_due, ...); none without one.",
            "type": [
              "string",
              "null"
            ]
          },
          "used": {
            "description": "Inboxes the account has.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "active",
          "price_cents",
          "required",
          "seats",
          "used"
        ],
        "type": "object"
      },
      "InboxCheckout": {
        "description": "`POST /v1/inboxes/billing/checkout`: how many inboxes to buy (default: yours plus one).",
        "properties": {
          "quantity": {
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "InboxMessage": {
        "description": "A received message. Lists leave out `text` and `html`; get one message for them.",
        "properties": {
          "codes": {
            "default": [],
            "description": "One-time codes found in the subject and body, most likely first.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "envelope_from": {
            "default": "",
            "description": "The SMTP envelope sender (bounce address); may differ from `from`.",
            "type": "string"
          },
          "from": {
            "description": "The From header's address.",
            "type": "string"
          },
          "from_name": {
            "default": "",
            "type": "string"
          },
          "html": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "inbox_id": {
            "type": "string"
          },
          "links": {
            "default": [],
            "description": "Verification, confirmation and sign-in links found in the body, most likely first.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "preview": {
            "default": "",
            "description": "The first 200 characters of the text.",
            "type": "string"
          },
          "received_at": {
            "format": "int64",
            "type": "integer"
          },
          "size": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "subject": {
            "type": "string"
          },
          "text": {
            "type": [
              "string",
              "null"
            ]
          },
          "to": {
            "type": "string"
          }
        },
        "required": [
          "from",
          "id",
          "inbox_id",
          "received_at",
          "size",
          "subject",
          "to"
        ],
        "type": "object"
      },
      "InboxMessageList": {
        "properties": {
          "messages": {
            "description": "Newest first.",
            "items": {
              "$ref": "#/components/schemas/InboxMessage"
            },
            "type": "array"
          }
        },
        "required": [
          "messages"
        ],
        "type": "object"
      },
      "InboxWait": {
        "description": "`GET /v1/inboxes/{inbox}/wait`: the first matching message, or none when the wait timed out.",
        "properties": {
          "message": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/InboxMessage"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object"
      },
      "InterruptRequest": {
        "properties": {
          "conversation_id": {
            "description": "Only this conversation (default: every conversation on the sandbox).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "InterruptResult": {
        "properties": {
          "interrupted": {
            "description": "The prompts stopped (running) or cancelled (queued).",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "interrupted"
        ],
        "type": "object"
      },
      "Ipv4Port": {
        "description": "An opened port's public IPv4 address: the host's address and a port of its own, forwarded to the sandbox's port.",
        "properties": {
          "address": {
            "description": "Connect here over IPv4: \"203.0.113.7:40001\".",
            "type": "string"
          },
          "port": {
            "description": "The sandbox's port, \"8080/tcp\".",
            "type": "string"
          },
          "public_port": {
            "description": "The port on the host's IPv4 address that forwards to it.",
            "format": "uint16",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "address",
          "port",
          "public_port"
        ],
        "type": "object"
      },
      "Job": {
        "description": "A background command. `state`: running | paused (frozen with a sandbox stopped with its memory kept; a start resumes it) | exited | killed | lost (the sandbox stopped under it).",
        "properties": {
          "command": {
            "description": "First 200 characters.",
            "type": "string"
          },
          "command_id": {
            "description": "The job's record in the command history (None for jobs froog started itself, like setup).",
            "type": [
              "string",
              "null"
            ]
          },
          "exit_code": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "started_at": {
            "format": "int64",
            "type": "integer"
          },
          "state": {
            "type": "string"
          }
        },
        "required": [
          "command",
          "id",
          "started_at",
          "state"
        ],
        "type": "object"
      },
      "JobOutput": {
        "description": "A job's state and a chunk of its output (stdout and stderr together), read from `offset`. Pass `next_offset` as the next `offset` to follow it.",
        "properties": {
          "exit_code": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "next_offset": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "output": {
            "type": "string"
          },
          "output_size": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "started_at": {
            "format": "int64",
            "type": "integer"
          },
          "state": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "next_offset",
          "output",
          "output_size",
          "started_at",
          "state"
        ],
        "type": "object"
      },
      "JobStdin": {
        "description": "Write to a running job's standard input (one started with `stdin_open`), and/or close it.",
        "properties": {
          "close": {
            "description": "Close the input after writing: the command reads end of file.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "data": {
            "description": "Text to write (at most 1 MiB).",
            "type": [
              "string",
              "null"
            ]
          },
          "data_b64": {
            "description": "Like `data`, base64-encoded (at most 1 MiB decoded).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "JsonRpcError": {
        "properties": {
          "code": {
            "description": "-32700 parse error, -32600 invalid request, -32601 unknown method, -32602 bad params.",
            "format": "int64",
            "type": "integer"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "message"
        ],
        "type": "object"
      },
      "JsonRpcRequest": {
        "description": "A JSON-RPC 2.0 message to `POST /mcp` (a batch is an array of them). Without `id` it's a notification, answered with 202 and no body.",
        "properties": {
          "id": true,
          "jsonrpc": {
            "description": "Always \"2.0\".",
            "type": "string"
          },
          "method": {
            "description": "initialize, ping, tools/list, tools/call, notifications/initialized, …",
            "type": "string"
          },
          "params": true
        },
        "required": [
          "jsonrpc",
          "method"
        ],
        "type": "object"
      },
      "JsonRpcResponse": {
        "description": "The answer to a JSON-RPC request: `result` or `error`. A failed tool call is a `result` with `isError: true` and the API error (`code`, `message`, `request_id`) as its text.",
        "properties": {
          "error": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/JsonRpcError"
              },
              {
                "type": "null"
              }
            ]
          },
          "id": true,
          "jsonrpc": {
            "type": "string"
          },
          "result": true
        },
        "required": [
          "id",
          "jsonrpc"
        ],
        "type": "object"
      },
      "Limits": {
        "description": "What an account may do now: `GET /v1/limits`.",
        "properties": {
          "max_sandboxes": {
            "description": "Sandboxes at once (lower during the free trial).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "plan_nudge": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PlanNudge"
              },
              {
                "type": "null"
              }
            ],
            "description": "Only when another plan fits the last 30 days' usage better."
          },
          "running": {
            "description": "Running or starting now.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "saved_snapshot_allowance": {
            "$ref": "#/components/schemas/SavedSnapshotAllowance",
            "default": {
              "extra": 0,
              "included": 0,
              "price_per_extra_day_usd": 0.0,
              "used": 0
            },
            "description": "Saved snapshots included in the plan vs kept now."
          },
          "sizes": {
            "description": "Sizes the account can start.",
            "items": {
              "$ref": "#/components/schemas/Size"
            },
            "type": "array"
          },
          "starts": {
            "$ref": "#/components/schemas/StartLimits"
          },
          "trial": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Trial"
              },
              {
                "type": "null"
              }
            ],
            "description": "The free trial; None when this account has none (billing off, or exempt)."
          }
        },
        "required": [
          "max_sandboxes",
          "running",
          "sizes",
          "starts"
        ],
        "type": "object"
      },
      "MakeDir": {
        "properties": {
          "mode": {
            "description": "Octal permissions of the new directory, e.g. 700 (default: the umask's, usually 755).",
            "type": [
              "string",
              "null"
            ]
          },
          "path": {
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "type": "object"
      },
      "MetricsHistory": {
        "description": "`GET /sandboxes/{name}/metrics/history`: CPU, memory and disk sampled every 30 seconds while the sandbox runs (monitoring on), kept 7 days, averaged per `step_secs`, oldest first. Times when it was stopped have no points.",
        "properties": {
          "points": {
            "items": {
              "$ref": "#/components/schemas/MetricsPoint"
            },
            "type": "array"
          },
          "since": {
            "description": "The window, unix seconds.",
            "format": "int64",
            "type": "integer"
          },
          "step_secs": {
            "description": "Each point averages this many seconds (a multiple of 30; at most 1000 points).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "until": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "points",
          "since",
          "step_secs",
          "until"
        ],
        "type": "object"
      },
      "MetricsPoint": {
        "properties": {
          "at": {
            "description": "The bucket's start, unix seconds.",
            "format": "int64",
            "type": "integer"
          },
          "cpu_max_percent": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "cpu_percent": {
            "description": "Share of all CPUs busy (0-100), the average and the highest sample in the bucket.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "disk_used_percent": {
            "description": "Of the root filesystem.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "memory_total_mb": {
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "memory_used_mb": {
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "samples": {
            "description": "Samples in the bucket.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "at",
          "samples"
        ],
        "type": "object"
      },
      "MoveFile": {
        "properties": {
          "from": {
            "type": "string"
          },
          "to": {
            "type": "string"
          }
        },
        "required": [
          "from",
          "to"
        ],
        "type": "object"
      },
      "NewApiKey": {
        "properties": {
          "actions": {
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "environments": {
            "description": "Limit the key to sandboxes of these environments (names). Sandboxes it creates use the first one unless they name another of them.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "labels": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Limit the key to sandboxes that have all of these labels. Sandboxes it creates or forks get them, and it can't change or remove them.",
            "type": [
              "object",
              "null"
            ]
          },
          "never_expires": {
            "default": false,
            "description": "A key that works until revoked.",
            "type": "boolean"
          },
          "preset": {
            "description": "read-only | full-sandbox | ci | admin (`scopes::PRESETS`). Use this or `actions`.",
            "type": [
              "string",
              "null"
            ]
          },
          "sandboxes": {
            "description": "Limit the key to these sandboxes (names), plus any it creates.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "ttl_days": {
            "default": null,
            "description": "Days until it expires (1-365). Default 90.",
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "NewEnvironment": {
        "description": "`POST /environments`",
        "properties": {
          "copy_from": {
            "description": "Start with a copy of this environment's latest version (repos, scripts, secret files). Default: empty.",
            "type": [
              "string",
              "null"
            ]
          },
          "default": {
            "description": "Make it the default right away.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "NewFile": {
        "description": "A file to write into a new sandbox (`CreateSandbox.files`).",
        "properties": {
          "content": {
            "type": "string"
          },
          "encoding": {
            "description": "utf8 (default) or base64 (for binary files).",
            "type": [
              "string",
              "null"
            ]
          },
          "path": {
            "description": "Relative to the home directory, e.g. `app/.env`.",
            "type": "string"
          }
        },
        "required": [
          "content",
          "path"
        ],
        "type": "object"
      },
      "NewFileUrl": {
        "description": "`POST /sandboxes/{name}/files/download-url` or `/upload-url`.",
        "properties": {
          "expires_in": {
            "description": "Seconds the URL works (60-86400, default 900).",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "path": {
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "type": "object"
      },
      "NewJob": {
        "description": "Start a background command: `POST /sandboxes/{name}/jobs`.",
        "properties": {
          "command": {
            "type": "string"
          },
          "cwd": {
            "description": "Run in this directory (relative to the home directory, or absolute).",
            "type": [
              "string",
              "null"
            ]
          },
          "env": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Extra environment variables for this command only.",
            "type": [
              "object",
              "null"
            ]
          },
          "mode": {
            "description": "\"detached\" (default) or \"stream\" (`froog exec --timeout 0` follows it); shown in the history.",
            "type": [
              "string",
              "null"
            ]
          },
          "stdin": {
            "description": "Text for the job's standard input, given at start (at most 1 MiB). Kept with the job on the sandbox's disk (`~/.froog/jobs/<id>/stdin`).",
            "type": [
              "string",
              "null"
            ]
          },
          "stdin_b64": {
            "description": "Like `stdin`, base64-encoded (at most 1 MiB decoded).",
            "type": [
              "string",
              "null"
            ]
          },
          "stdin_open": {
            "description": "Keep standard input open: write to it later with `POST /jobs/{id}/stdin` (after `stdin`, if given), and close it there for end of file.",
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "required": [
          "command"
        ],
        "type": "object"
      },
      "NewPublicUrl": {
        "description": "`POST /sandboxes/{name}/urls`: host a port, or change how an already hosted port is reached.",
        "properties": {
          "port": {
            "format": "uint16",
            "minimum": 0.0,
            "type": "integer"
          },
          "public": {
            "default": false,
            "description": "true: no token. Default false (private), like boat. Hosting a public port again without it gives it a new token; with it, removes the token.",
            "type": "boolean"
          },
          "subdomain": {
            "description": "Rename the URL to `https://<subdomain>.<domain>` (3-40 lowercase letters, digits, hyphens).",
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "description": "A label for people (at most 100 characters); \"\" removes it. Hosting again without it keeps the old one.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "port"
        ],
        "type": "object"
      },
      "NewUrlToken": {
        "description": "`POST /sandboxes/{name}/urls/{port}/tokens`: another token for a private URL, e.g. one per viewer, that expires and can be revoked on its own.",
        "properties": {
          "label": {
            "description": "Who or what it's for (at most 100 characters).",
            "type": [
              "string",
              "null"
            ]
          },
          "ttl_secs": {
            "description": "Seconds until it stops working: 60 to 30 days, default 1 day.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "NewWebhook": {
        "properties": {
          "events": {
            "default": [],
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "url"
        ],
        "type": "object"
      },
      "OpenPort": {
        "description": "`POST /sandboxes/{name}/ports`: open one inbound port (on the sandbox's IPv6 address, and on a public port of its host's IPv4 address).",
        "properties": {
          "port": {
            "format": "uint16",
            "minimum": 0.0,
            "type": "integer"
          },
          "protocol": {
            "default": "tcp",
            "description": "tcp (default) or udp.",
            "type": "string"
          }
        },
        "required": [
          "port"
        ],
        "type": "object"
      },
      "OrgSummary": {
        "description": "One workspace in `GET /orgs`: your personal account first, then each organization.",
        "properties": {
          "active": {
            "description": "The active workspace: requests that name none use it (CLI, account API keys).",
            "type": "boolean"
          },
          "id": {
            "description": "`personal`, or the organization id (`org_…`).",
            "type": "string"
          },
          "kind": {
            "description": "personal | org",
            "type": "string"
          },
          "members": {
            "default": 0,
            "description": "Members (1 for personal).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "role": {
            "description": "Your role: owner | admin | member (`owner` for personal).",
            "type": "string"
          }
        },
        "required": [
          "active",
          "id",
          "kind",
          "name",
          "role"
        ],
        "type": "object"
      },
      "Os": {
        "description": "The operating system a sandbox runs. All come with the same tools. `omarchy` is Arch Linux with Omarchy's Hyprland desktop (a sandbox with a screen). Accepts the id or the distro's name (\"debian\").",
        "enum": [
          "ubuntu-24.04",
          "ubuntu-26.04",
          "debian-13",
          "omarchy"
        ],
        "type": "string"
      },
      "OsImage": {
        "description": "An OS sandboxes can start with: `GET /v1/images`.",
        "properties": {
          "default": {
            "type": "boolean"
          },
          "id": {
            "$ref": "#/components/schemas/Os"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "default",
          "id",
          "name"
        ],
        "type": "object"
      },
      "PlanChange": {
        "description": "What choosing a plan did: a Checkout page to open (first plan), or the plan changed.",
        "properties": {
          "billing": {
            "$ref": "#/components/schemas/Billing"
          },
          "url": {
            "description": "Open this Stripe page to subscribe (and save a card). None = changed already.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "billing"
        ],
        "type": "object"
      },
      "PlanInfo": {
        "description": "A plan on offer.",
        "properties": {
          "max_sandboxes": {
            "description": "Sandboxes at once.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "saved_snapshots": {
            "description": "Saved snapshots included.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "usd": {
            "description": "Dollars a month, all of it usable as running time and storage.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "xlarge": {
            "default": false,
            "description": "The plan can start `xlarge` sandboxes.",
            "type": "boolean"
          }
        },
        "required": [
          "max_sandboxes",
          "saved_snapshots",
          "usd"
        ],
        "type": "object"
      },
      "PlanNudge": {
        "description": "In `GET /limits`, only when another plan fits the last 30 days' usage better.",
        "properties": {
          "text": {
            "description": "The suggestion, with the sum.",
            "type": "string"
          },
          "usd": {
            "description": "The plan that fits, dollars a month.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "used_usd": {
            "description": "Running time used in the last 30 days, at list prices.",
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "text",
          "usd",
          "used_usd"
        ],
        "type": "object"
      },
      "PortEvent": {
        "description": "One line of `GET /sandboxes/{name}/ports/watch` (NDJSON). `type`: `ready`, then `open` / `close` (`port`, `protocol` tcp) as TCP ports start or stop listening (the ones already listening come first as `open`), and last `end` (`reason`, `message`).",
        "properties": {
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "port": {
            "format": "uint16",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "protocol": {
            "type": [
              "string",
              "null"
            ]
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string"
          }
        },
        "required": [
          "type"
        ],
        "type": "object"
      },
      "PortWait": {
        "description": "The answer to `POST /sandboxes/{name}/wait`.",
        "properties": {
          "port": {
            "format": "uint16",
            "minimum": 0.0,
            "type": "integer"
          },
          "ready": {
            "description": "true: something listens on the port (on any address); false: the timeout passed first.",
            "type": "boolean"
          },
          "waited_ms": {
            "description": "How long it waited, in milliseconds.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "port",
          "ready",
          "waited_ms"
        ],
        "type": "object"
      },
      "Ports": {
        "description": "Inbound ports open on a sandbox (`GET /sandboxes/{name}/ports`): on its public IPv6 address as they are, and the explicitly opened ones also on a public port of its host's IPv4 address (`ipv4`). They stay open across stops and starts.",
        "properties": {
          "from_urls": {
            "default": [],
            "description": "The ones open because a public URL serves that TCP port: they close with the URL (or when it's made private) unless they were also opened on their own.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "ipv4": {
            "description": "Where the explicitly opened ports are reached over IPv4: sandboxes share their host's IPv4 address, so each gets a public port of its own there. Empty while stopped (a start gives them again, the same ones when it lands on the same host) and for public URLs' ports.",
            "items": {
              "$ref": "#/components/schemas/Ipv4Port"
            },
            "type": "array"
          },
          "ipv4_note": {
            "description": "Why some opened ports have no IPv4 address (stopped, a limit reached, the host's range full).",
            "type": [
              "string",
              "null"
            ]
          },
          "ports": {
            "description": "Everything open besides SSH, as \"8080/tcp\" or \"27015/udp\", sorted.",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "ports"
        ],
        "type": "object"
      },
      "ProcessInfo": {
        "description": "A process in a sandbox (`GET /sandboxes/{name}/processes`), busiest first.",
        "properties": {
          "command": {
            "type": "string"
          },
          "command_id": {
            "description": "The history record of the command this process belongs to, if any.",
            "type": [
              "string",
              "null"
            ]
          },
          "cpu_percent": {
            "format": "double",
            "type": "number"
          },
          "memory_mb": {
            "format": "double",
            "type": "number"
          },
          "pid": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "user": {
            "type": "string"
          }
        },
        "required": [
          "command",
          "cpu_percent",
          "memory_mb",
          "pid",
          "user"
        ],
        "type": "object"
      },
      "ProcessList": {
        "description": "`live`: false when the sandbox isn't running and this is the last sample kept (`sampled_at`).",
        "properties": {
          "live": {
            "type": "boolean"
          },
          "processes": {
            "items": {
              "$ref": "#/components/schemas/ProcessInfo"
            },
            "type": "array"
          },
          "sampled_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "total": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "live",
          "processes",
          "total"
        ],
        "type": "object"
      },
      "ProcessRecord": {
        "properties": {
          "command": {
            "description": "Its command line (up to 1024 characters).",
            "type": "string"
          },
          "ended_at": {
            "description": "The first sample it was missing from: it ended between `last_seen_at` and this. None while it runs.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "last_seen_at": {
            "description": "The last sample it was in.",
            "format": "int64",
            "type": "integer"
          },
          "pid": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "ppid": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "started_at": {
            "description": "Unix seconds (from its elapsed time when first seen).",
            "format": "int64",
            "type": "integer"
          },
          "user": {
            "type": "string"
          }
        },
        "required": [
          "command",
          "last_seen_at",
          "pid",
          "ppid",
          "started_at",
          "user"
        ],
        "type": "object"
      },
      "ProcessRecords": {
        "description": "`GET /sandboxes/{name}/processes/records`: processes seen in the 30-second samples (monitoring on), kept 72 hours after they end, newest start first. A process that starts and ends between two samples isn't recorded.",
        "properties": {
          "records": {
            "items": {
              "$ref": "#/components/schemas/ProcessRecord"
            },
            "type": "array"
          }
        },
        "required": [
          "records"
        ],
        "type": "object"
      },
      "ProcessSamples": {
        "description": "`GET /sandboxes/{name}/processes/samples`: the 12 busiest processes, sampled every 30 seconds while the sandbox runs and kept 7 days, newest first.",
        "properties": {
          "samples": {
            "items": {
              "$ref": "#/components/schemas/ProcessList"
            },
            "type": "array"
          }
        },
        "required": [
          "samples"
        ],
        "type": "object"
      },
      "Prompt": {
        "description": "One prompt (a turn of a conversation).",
        "properties": {
          "agent": {
            "type": "string"
          },
          "attachments": {
            "default": [],
            "description": "Paths of its attachments in the sandbox.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "conversation_id": {
            "type": "string"
          },
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "done": {
            "description": "done, failed or interrupted.",
            "type": "boolean"
          },
          "effort": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "description": "Why it failed (failed prompts).",
            "type": [
              "string",
              "null"
            ]
          },
          "error_code": {
            "description": "e.g. provider_not_configured, timed_out, sandbox_stopped.",
            "type": [
              "string",
              "null"
            ]
          },
          "exit_code": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "fast": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "finished_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "model": {
            "type": [
              "string",
              "null"
            ]
          },
          "prompt": {
            "description": "The prompt text (empty for a sandbox with monitoring off, once it started).",
            "type": "string"
          },
          "result": {
            "description": "The agent's final answer (done prompts).",
            "type": [
              "string",
              "null"
            ]
          },
          "sandbox": {
            "type": "string"
          },
          "started_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "status": {
            "description": "queued | running | done | failed | interrupted",
            "type": "string"
          }
        },
        "required": [
          "agent",
          "conversation_id",
          "created_at",
          "done",
          "id",
          "prompt",
          "sandbox",
          "status"
        ],
        "type": "object"
      },
      "PromptAttachment": {
        "description": "A file sent with a prompt (`attachments`): saved in the sandbox under `~/attachments/<prompt id>/<name>`, and its path given to the agent.",
        "properties": {
          "content_b64": {
            "description": "The file's bytes, base64.",
            "type": "string"
          },
          "name": {
            "description": "File name (no directories), e.g. \"error.png\".",
            "type": "string"
          }
        },
        "required": [
          "content_b64",
          "name"
        ],
        "type": "object"
      },
      "PromptList": {
        "properties": {
          "prompts": {
            "items": {
              "$ref": "#/components/schemas/Prompt"
            },
            "type": "array"
          }
        },
        "required": [
          "prompts"
        ],
        "type": "object"
      },
      "PromptRequest": {
        "properties": {
          "agent": {
            "description": "The harness: claude (default), codex, gemini, opencode, pi, amp, cursor, prime, kimi or mistral.",
            "type": [
              "string",
              "null"
            ]
          },
          "attachments": {
            "description": "Images, PDFs or other files for the agent: up to 12, 25 MB each, 64 MB in total.",
            "items": {
              "$ref": "#/components/schemas/PromptAttachment"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "conversation_id": {
            "description": "Continue this conversation (default: the sandbox's most recent one).",
            "type": [
              "string",
              "null"
            ]
          },
          "effort": {
            "description": "Reasoning effort / thinking level, for harnesses that take one (claude, codex, pi, prime, kimi).",
            "type": [
              "string",
              "null"
            ]
          },
          "fast": {
            "description": "Fast mode (same model, faster output at the provider's fast rate): claude (Opus) and codex. false forces standard speed.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "model": {
            "description": "Passed to the harness's model flag, e.g. \"opus\", \"gpt-6.1-sol\", \"anthropic/claude-sonnet-4-5\" (`GET /provider-models`).",
            "type": [
              "string",
              "null"
            ]
          },
          "new": {
            "description": "Start a new conversation.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "prompt": {
            "type": "string"
          },
          "timeout_secs": {
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "PromptResult": {
        "description": "What `POST /sandboxes/{name}/prompt` (wait for the answer) returns.",
        "properties": {
          "conversation_id": {
            "type": "string"
          },
          "exit_code": {
            "description": "0 when the agent finished; 124 when it timed out.",
            "format": "int32",
            "type": "integer"
          },
          "prompt_id": {
            "type": "string"
          },
          "status": {
            "description": "done | failed | interrupted | running (still running when the wait timed out)",
            "type": "string"
          },
          "stderr": {
            "description": "Why it failed, if it did.",
            "type": "string"
          },
          "stdout": {
            "description": "The agent's final answer.",
            "type": "string"
          },
          "timed_out": {
            "type": "boolean"
          }
        },
        "required": [
          "conversation_id",
          "exit_code",
          "prompt_id",
          "status",
          "stderr",
          "stdout",
          "timed_out"
        ],
        "type": "object"
      },
      "ProviderModel": {
        "description": "One model of a harness in the catalog.",
        "properties": {
          "efforts": {
            "description": "Accepted `effort` levels (empty: none).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "fast_mode": {
            "description": "Takes `fast: true`.",
            "type": "boolean"
          },
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "efforts",
          "fast_mode",
          "id",
          "title"
        ],
        "type": "object"
      },
      "ProviderModels": {
        "description": "A harness and the models it accepts.",
        "properties": {
          "agent": {
            "description": "The `agent` value.",
            "type": "string"
          },
          "aliases": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "any_model": {
            "description": "Takes model ids beyond `models` (e.g. `openrouter/…`, full model ids).",
            "type": "boolean"
          },
          "efforts": {
            "description": "Effort levels of the harness.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "fast_mode": {
            "description": "Has a fast mode.",
            "type": "boolean"
          },
          "keys": {
            "description": "Env vars it runs on (any one).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "live_models": {
            "description": "Model ids the harness listed in the sandbox (`?sandbox=`; harnesses that can list them).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "models": {
            "items": {
              "$ref": "#/components/schemas/ProviderModel"
            },
            "type": "array"
          },
          "steer": {
            "description": "Takes a message in the middle of a running turn (`steer`).",
            "type": "boolean"
          },
          "takes_model": {
            "description": "Takes `model` at all.",
            "type": "boolean"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "agent",
          "aliases",
          "any_model",
          "efforts",
          "fast_mode",
          "keys",
          "models",
          "steer",
          "takes_model",
          "title"
        ],
        "type": "object"
      },
      "PublicUrl": {
        "description": "A public HTTPS URL for a port inside a sandbox.",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "port": {
            "format": "uint16",
            "minimum": 0.0,
            "type": "integer"
          },
          "public": {
            "default": true,
            "description": "false: only people with the token (in the URL, or the `__Host-froog_url` cookie) get through.",
            "type": "boolean"
          },
          "title": {
            "description": "A label for people, e.g. \"API docs\".",
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "description": "For a private URL, includes `?_token=…`: treat it like a password.",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "port",
          "url"
        ],
        "type": "object"
      },
      "Rate": {
        "description": "What a size costs to run, billed per second.",
        "properties": {
          "per_hour_usd": {
            "format": "double",
            "type": "number"
          },
          "per_month_usd": {
            "description": "A full month (730 hours).",
            "format": "double",
            "type": "number"
          },
          "size": {
            "$ref": "#/components/schemas/Size"
          }
        },
        "required": [
          "per_hour_usd",
          "per_month_usd",
          "size"
        ],
        "type": "object"
      },
      "Restore": {
        "properties": {
          "snapshot": {
            "type": "string"
          }
        },
        "required": [
          "snapshot"
        ],
        "type": "object"
      },
      "Sandbox": {
        "properties": {
          "access": {
            "description": "In an organization: what you may do with it. `owner` (you created it), `use` (a shared sandbox) or `view` (a teammate's private sandbox: see it and its usage).",
            "type": [
              "string",
              "null"
            ]
          },
          "auto_start": {
            "default": false,
            "description": "While stopped, a request to one of its public URLs, or an exec, file, job or wait call, starts it (billed and limited like any start).",
            "type": "boolean"
          },
          "auto_stop_at": {
            "description": "While running with an auto-stop timer: when it stops (unix seconds). A running agent prompt moves it one `ttl_secs` later; `PATCH ttl_secs` sets it to now + ttl_secs.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "backend": {
            "type": "string"
          },
          "created_at": {
            "description": "Unix seconds.",
            "format": "int64",
            "type": "integer"
          },
          "created_by": {
            "description": "In an organization: the email of the member who created it (absent for personal sandboxes and for those the organization made itself, such as CI jobs).",
            "type": [
              "string",
              "null"
            ]
          },
          "delete_after_secs": {
            "default": 0,
            "description": "Deleted after staying stopped this many seconds. 0 = never.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "delete_at": {
            "description": "While stopped with `delete_after_secs`: when it will be deleted (unix seconds).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "disk_expired": {
            "default": false,
            "description": "Set once the disk of a stopped sandbox was deleted; start and fork then fail.",
            "type": "boolean"
          },
          "disk_expires_at": {
            "default": null,
            "description": "For a stopped sandbox: when its disk will be deleted (save a snapshot to keep it longer).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "disk_used_percent": {
            "description": "Disk use of a running sandbox in percent (checked every 30 seconds).",
            "format": "uint8",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "env": {
            "description": "Names of its own environment variables (values are never returned).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "environment": {
            "default": true,
            "description": "false: it runs without its environment (`--no-environment`).",
            "type": "boolean"
          },
          "environment_name": {
            "description": "The environment it belongs to (`default` unless it was created with another), also when it runs without it (`environment: false`).",
            "type": [
              "string",
              "null"
            ]
          },
          "environment_version": {
            "description": "The version of that environment it is on: the latest when it was created; it moves only with `POST /environments/{env}/upgrade` (or a start with `environment_name`).",
            "format": "uint32",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "expires_at": {
            "description": "A deadline: deleted at this time (unix seconds) whatever its state, like a TTL from creation (`expires_in_secs`). Saved snapshots stay.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "forked_from": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SandboxOrigin"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where its disk came from, when it was forked or started from a saved snapshot (absent for new sandboxes, ones from a share code, and those made before this was recorded)."
          },
          "ipv4": {
            "type": [
              "string",
              "null"
            ]
          },
          "ipv6": {
            "description": "Its own public IPv6 address (inbound: SSH and its open ports, `/sandboxes/{name}/ports`). None while stopped; it can change at a start (not at a warm resume).",
            "type": [
              "string",
              "null"
            ]
          },
          "labels": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Your own key-value tags (`label=key=value` filters lists).",
            "type": "object"
          },
          "last_active_at": {
            "format": "int64",
            "type": "integer"
          },
          "last_reboot": {
            "description": "When its operating system last booted: a start from its disk, a restart after a crash or a host restart, or a reboot inside it (a warm resume isn't a reboot). Unix seconds.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "max_lifetime_secs": {
            "default": 0,
            "description": "Stopped this many seconds after each start, busy or not. 0 = no limit.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "monitoring": {
            "default": true,
            "description": "false: no command history or process samples.",
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "os": {
            "$ref": "#/components/schemas/Os",
            "default": "ubuntu-24.04"
          },
          "period_cost_usd": {
            "description": "What its running time cost in the current billing period, at list prices (in lists and info; saved snapshots are billed per account, not here).",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "progress": {
            "description": "While creating or starting: what takes the time, e.g. copying its disk from another host.",
            "type": [
              "string",
              "null"
            ]
          },
          "repo": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SandboxRepo"
              },
              {
                "type": "null"
              }
            ],
            "description": "The repo cloned into this sandbox at create (`CreateSandbox.repo`)."
          },
          "setup_error": {
            "description": "Why setup failed: its error lines (a failed clone, a script's exit code).",
            "type": [
              "string",
              "null"
            ]
          },
          "setup_status": {
            "default": "none",
            "description": "The setup job (repos, the environment's setup script, `new --setup`) of the last boot: none | running | done | failed.",
            "type": "string"
          },
          "size": {
            "$ref": "#/components/schemas/Size"
          },
          "snapshots": {
            "default": true,
            "description": "false: never snapshotted; a stop erases it (no start, fork or restore).",
            "type": "boolean"
          },
          "ssh_port": {
            "default": 22,
            "description": "SSH port at `ipv4` (VMs on a shared host each have their own).",
            "format": "uint16",
            "minimum": 0.0,
            "type": "integer"
          },
          "started_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "state": {
            "$ref": "#/components/schemas/State"
          },
          "stop_at": {
            "description": "While running with `max_lifetime_secs`: when it will be stopped (unix seconds).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "stop_error": {
            "description": "Why the stop was refused: the last snapshot error.",
            "type": [
              "string",
              "null"
            ]
          },
          "stop_id": {
            "description": "Only in the answer to `POST /sandboxes/{name}/stop`: the stop's id, for `GET /stops/{id}`.",
            "type": [
              "string",
              "null"
            ]
          },
          "stop_refused_at": {
            "description": "Set while a stop is refused because its snapshot failed: since when. The sandbox keeps running, unbilled, and froog retries the stop until a snapshot works (a forced stop after 3 days); a start cancels the stop.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "ttl_secs": {
            "description": "The auto-stop timer: it stops this many seconds after each start (or resume), busy or not, unless an agent prompt is running. 0 = no auto-stop.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "unresponsive_since": {
            "description": "Set while a running sandbox doesn't answer (commands and SSH hang): since when. Billing pauses meanwhile; after 3 days it's stopped onto its last snapshot.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "visibility": {
            "description": "In an organization: `shared` (every member can use it) or `private` (only its creator).",
            "type": [
              "string",
              "null"
            ]
          },
          "warm_until": {
            "description": "Stopped, with its memory kept until then: a start before it resumes every running program in about a second (after it, the start boots from the disk snapshot).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "backend",
          "created_at",
          "last_active_at",
          "name",
          "size",
          "state",
          "ttl_secs"
        ],
        "type": "object"
      },
      "SandboxAi": {
        "description": "One sandbox's AI settings and usage (`GET /v1/sandboxes/{name}/ai`).",
        "properties": {
          "blocked": {
            "description": "Its AI requests are refused.",
            "type": "boolean"
          },
          "days": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "profile": {
            "description": "The profile it uses (its own, its environment's, or the default).",
            "type": [
              "string",
              "null"
            ]
          },
          "profile_set": {
            "description": "Set on the sandbox itself (else it follows its environment).",
            "type": "boolean"
          },
          "proxied": {
            "description": "It holds placeholders now (the proxy was on at its last start).",
            "type": "boolean"
          },
          "sandbox": {
            "type": "string"
          },
          "totals": {
            "$ref": "#/components/schemas/AiTotals"
          },
          "usage": {
            "items": {
              "$ref": "#/components/schemas/AiUsageRow"
            },
            "type": "array"
          }
        },
        "required": [
          "blocked",
          "days",
          "profile_set",
          "proxied",
          "sandbox",
          "totals",
          "usage"
        ],
        "type": "object"
      },
      "SandboxMetrics": {
        "description": "`GET /sandboxes/{name}/metrics`: one sample read from the running sandbox now.",
        "properties": {
          "cpu_count": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "cpu_percent": {
            "description": "Share of all CPUs busy over half a second (0-100).",
            "format": "double",
            "type": "number"
          },
          "disk_total_bytes": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "disk_used_bytes": {
            "description": "Of the root filesystem.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "io_pressure": {
            "description": "Share of the last minute some task waited for disk I/O (0-1).",
            "format": "double",
            "type": "number"
          },
          "memory_total_bytes": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "memory_used_bytes": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "network_rx_bytes": {
            "description": "Received and sent since boot, all interfaces but loopback.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "network_tx_bytes": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "sampled_at": {
            "description": "Unix seconds.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "cpu_count",
          "cpu_percent",
          "disk_total_bytes",
          "disk_used_bytes",
          "io_pressure",
          "memory_total_bytes",
          "memory_used_bytes",
          "network_rx_bytes",
          "network_tx_bytes",
          "sampled_at"
        ],
        "type": "object"
      },
      "SandboxOrigin": {
        "description": "`Sandbox.forked_from`: the sandbox and snapshot a fork (or a start from a saved snapshot) copied its disk from.",
        "properties": {
          "at": {
            "description": "Unix seconds: when the copy was made.",
            "format": "int64",
            "type": "integer"
          },
          "label": {
            "description": "The snapshot's name, when it has one.",
            "type": [
              "string",
              "null"
            ]
          },
          "sandbox": {
            "description": "The source sandbox's name (it may have been deleted or renamed since).",
            "type": "string"
          },
          "snapshot": {
            "description": "The snapshot's id (`snap_…`); absent for a fork of the source's state at that moment.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "at",
          "sandbox"
        ],
        "type": "object"
      },
      "SandboxRepo": {
        "description": "A repo cloned into one sandbox (`CreateSandbox.repo`), like the account's repos: at boot, when the directory has no checkout yet. Credentials come from the sandbox's environment (`GH_TOKEN`, `~/.git-credentials`), never the URL.",
        "properties": {
          "branch": {
            "description": "Branch or tag to check out (default: the repo's default branch).",
            "type": [
              "string",
              "null"
            ]
          },
          "dir": {
            "description": "Directory relative to the home directory (default: the repo's name).",
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "description": "`https://`, `ssh://` or `git@` URL.",
            "type": "string"
          }
        },
        "required": [
          "url"
        ],
        "type": "object"
      },
      "SandboxUsage": {
        "description": "`GET /sandboxes/{name}/usage`: one sandbox's running time and cost in a window.",
        "properties": {
          "cost_usd": {
            "description": "At list prices (saved snapshots are billed per account, not here).",
            "format": "double",
            "type": "number"
          },
          "from": {
            "description": "The window, unix seconds (`to` is at most now).",
            "format": "int64",
            "type": "integer"
          },
          "lines": {
            "description": "One line per size it ran at.",
            "items": {
              "$ref": "#/components/schemas/UsageLine"
            },
            "type": "array"
          },
          "name": {
            "type": "string"
          },
          "seconds": {
            "description": "Running time in the window, billed per second.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "to": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "cost_usd",
          "from",
          "lines",
          "name",
          "seconds",
          "to"
        ],
        "type": "object"
      },
      "SavedSnapshot": {
        "description": "A saved snapshot of the account (`GET /saved-snapshots`): a template for `new --from NAME`. It outlives its source sandbox.",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "offsite": {
            "default": false,
            "description": "A copy is kept off the host, on separate storage (encrypted).",
            "type": "boolean"
          },
          "os": {
            "$ref": "#/components/schemas/Os"
          },
          "shared": {
            "default": false,
            "description": "It came from another account's share code (`new --from fsh_…`); `source` is the code's id.",
            "type": "boolean"
          },
          "size": {
            "$ref": "#/components/schemas/Size"
          },
          "size_gb": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "source": {
            "description": "The sandbox it was saved from.",
            "type": "string"
          },
          "source_deleted": {
            "description": "The source sandbox was deleted (the saved snapshot stays).",
            "type": "boolean"
          },
          "status": {
            "description": "creating | available",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "id",
          "name",
          "os",
          "size",
          "source",
          "source_deleted",
          "status"
        ],
        "type": "object"
      },
      "SavedSnapshotAllowance": {
        "description": "Saved snapshots the plan includes and how many the account keeps (`GET /limits`).",
        "properties": {
          "extra": {
            "description": "Above the included ones, billed per day.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "included": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "price_per_extra_day_usd": {
            "format": "double",
            "type": "number"
          },
          "used": {
            "description": "Saved snapshots (names) the account keeps now.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "extra",
          "included",
          "price_per_extra_day_usd",
          "used"
        ],
        "type": "object"
      },
      "SetAiEnvironmentProfile": {
        "description": "Which environment's sandboxes get which profile (`PUT /v1/ai/environments/{env}`).",
        "properties": {
          "profile": {
            "default": null,
            "description": "A profile name or id; null: the account's default profile.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "SetEnvFile": {
        "description": "`PUT /environment/files`",
        "properties": {
          "content": {
            "type": "string"
          },
          "path": {
            "type": "string"
          }
        },
        "required": [
          "content",
          "path"
        ],
        "type": "object"
      },
      "SetEnvVar": {
        "properties": {
          "value": {
            "type": "string"
          }
        },
        "required": [
          "value"
        ],
        "type": "object"
      },
      "SetExtraStarts": {
        "description": "`PUT /v1/billing/extra-starts`.",
        "properties": {
          "enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "enabled"
        ],
        "type": "object"
      },
      "SetPorts": {
        "description": "`PUT /sandboxes/{name}/ports`: the ports to open, replacing the ones opened before (\"8080/tcp\", \"27015/udp\"; a bare number is TCP). Public URLs' ports stay open regardless.",
        "properties": {
          "ports": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "ports"
        ],
        "type": "object"
      },
      "SetPrimary": {
        "description": "`PUT /v1/account/primary`: the connection whose address gets the account's emails.",
        "properties": {
          "connection": {
            "description": "A connection id (`con_…`).",
            "type": "string"
          }
        },
        "required": [
          "connection"
        ],
        "type": "object"
      },
      "SetTelemetry": {
        "description": "`PUT /telemetry`: the collector's base URL (froog adds /v1/metrics and /v1/logs) and the headers your vendor needs, e.g. `{\"dd-api-key\": \"…\"}`.",
        "properties": {
          "endpoint": {
            "type": "string"
          },
          "headers": {
            "additionalProperties": {
              "type": "string"
            },
            "default": {},
            "type": "object"
          }
        },
        "required": [
          "endpoint"
        ],
        "type": "object"
      },
      "SetTokenRepos": {
        "description": "`PUT /v1/github/token-repos`: limit the token in each sandbox to these repositories.",
        "properties": {
          "repos": {
            "description": "`owner/name`; empty = every repository the app can see.",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "repos"
        ],
        "type": "object"
      },
      "Size": {
        "description": "Machine sizes. Mapped to provider server types by the server's config.",
        "oneOf": [
          {
            "enum": [
              "small",
              "default",
              "large",
              "xlarge"
            ],
            "type": "string"
          },
          {
            "description": "No longer offered (was the $20 always-on VM: 2 vCPU, 8 GB, 100 GB).",
            "enum": [
              "standard"
            ],
            "type": "string"
          }
        ]
      },
      "Snapshot": {
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "type": "string"
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "offsite": {
            "default": false,
            "description": "A copy is kept off the host, on separate storage (encrypted), so the snapshot survives the loss of the machine. Usually true within minutes of the snapshot being taken.",
            "type": "boolean"
          },
          "sandbox": {
            "description": "The sandbox it belongs to (in account-wide lists and single lookups).",
            "type": [
              "string",
              "null"
            ]
          },
          "saved": {
            "description": "Saved snapshots are kept until deleted and billed per day; automatic ones are free.",
            "type": "boolean"
          },
          "size_gb": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "id",
          "saved",
          "status"
        ],
        "type": "object"
      },
      "SnapshotShare": {
        "description": "A share code of a saved snapshot, as listed (`GET /saved-snapshots/{name}/shares`). The code itself is shown only once, when it's made.",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "description": "`shr_…`",
            "type": "string"
          },
          "last_used_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "name": {
            "description": "The saved snapshot's name.",
            "type": "string"
          },
          "revoked_at": {
            "description": "Set once revoked: the code creates nothing any more.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "uses": {
            "description": "Sandboxes created from it so far.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "created_at",
          "id",
          "name",
          "uses"
        ],
        "type": "object"
      },
      "SshInfo": {
        "properties": {
          "host": {
            "type": "string"
          },
          "host_key": {
            "description": "OpenSSH public host key line, to pin in known_hosts.",
            "type": "string"
          },
          "port": {
            "format": "uint16",
            "minimum": 0.0,
            "type": "integer"
          },
          "user": {
            "type": "string"
          }
        },
        "required": [
          "host",
          "host_key",
          "port",
          "user"
        ],
        "type": "object"
      },
      "SshKey": {
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "public_key": {
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "id",
          "name",
          "public_key"
        ],
        "type": "object"
      },
      "StartBracket": {
        "description": "Starts up to `up_to` times the included number cost `price_usd` each.",
        "properties": {
          "price_usd": {
            "format": "double",
            "type": "number"
          },
          "up_to": {
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "price_usd",
          "up_to"
        ],
        "type": "object"
      },
      "StartLimits": {
        "description": "Sandbox starts (create, start, fork, restore) allowed per window; 0 = no limit.",
        "properties": {
          "per_day": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "per_hour": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "per_minute": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "used_day": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "used_hour": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "used_minute": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "per_day",
          "per_hour",
          "per_minute",
          "used_day",
          "used_hour",
          "used_minute"
        ],
        "type": "object"
      },
      "StartSandbox": {
        "description": "Optional body of `POST /sandboxes/{name}/start`.",
        "properties": {
          "env": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Environment variables set on top of the sandbox's own (these win; kept).",
            "type": [
              "object",
              "null"
            ]
          },
          "environment": {
            "description": "false: boot without the account's environment (env vars, repos, secret files, setup script, in-sandbox CLI key); true: with it. Default: as before. Kept for later starts.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "environment_name": {
            "description": "Move it to this environment's latest version (it also gets the environment again).",
            "type": [
              "string",
              "null"
            ]
          },
          "size": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Size"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start at a different size."
          },
          "ttl_secs": {
            "description": "A new auto-stop timer in seconds (0 = no auto-stop). Default: keep it.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "StartSubscriptionLogin": {
        "properties": {
          "sandbox": {
            "description": "A running sandbox to run the sign-in in (it runs `claude setup-token` or `codex login --device-auth` there; nothing is left behind).",
            "type": "string"
          }
        },
        "required": [
          "sandbox"
        ],
        "type": "object"
      },
      "State": {
        "enum": [
          "creating",
          "running",
          "stopping",
          "stopped",
          "starting",
          "restoring",
          "deleting",
          "deleted",
          "error"
        ],
        "type": "string"
      },
      "SteerRequest": {
        "properties": {
          "conversation_id": {
            "description": "The conversation to steer (default: the sandbox's current one).",
            "type": [
              "string",
              "null"
            ]
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "message"
        ],
        "type": "object"
      },
      "SteerResult": {
        "properties": {
          "conversation_id": {
            "type": "string"
          },
          "mode": {
            "description": "`native`: added to the running turn. `queued`: the harness can't take a message mid-turn, so it runs as the next turn of the same conversation (`queued_prompt_id`).",
            "type": "string"
          },
          "native": {
            "description": "The harness took the message into the running turn.",
            "type": "boolean"
          },
          "prompt_id": {
            "description": "The running prompt the message went to.",
            "type": "string"
          },
          "queued_prompt_id": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "conversation_id",
          "mode",
          "native",
          "prompt_id"
        ],
        "type": "object"
      },
      "Stop": {
        "description": "A stop (`GET /stops/{id}`): `POST /sandboxes/{name}/stop` returns its id, and an idle or billing stop gets one too. Stopping again while one is pending returns the same id.",
        "properties": {
          "ended_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "description": "`stop_…`",
            "type": "string"
          },
          "requested_at": {
            "description": "Unix seconds.",
            "format": "int64",
            "type": "integer"
          },
          "sandbox": {
            "description": "The sandbox's name.",
            "type": "string"
          },
          "status": {
            "description": "pending (snapshotting and shutting down) | failing (its snapshot failed, see `error`: the sandbox keeps running, unbilled, and froog retries this stop) | completed (stopped, or erased when it had snapshots off) | superseded (a start cancelled a failing stop) | failed (see `error`; the sandbox is in the error state, a start retries from its last snapshot).",
            "type": "string"
          }
        },
        "required": [
          "id",
          "requested_at",
          "sandbox",
          "status"
        ],
        "type": "object"
      },
      "StopSandbox": {
        "description": "Optional body of `POST /sandboxes/{name}/stop`.",
        "properties": {
          "force": {
            "default": false,
            "description": "Stop even when the stop snapshot fails: the sandbox then keeps its last good snapshot and loses what was written after it. Skips `~/.froog/pre-stop` and everything that needs the sandbox to answer, so it also stops one that's hung.",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "Subscription": {
        "description": "A subscription sign-in (Claude Pro/Max for Claude Code, ChatGPT for Codex).",
        "properties": {
          "agent": {
            "description": "The harness it signs in.",
            "type": "string"
          },
          "connected": {
            "type": "boolean"
          },
          "connected_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "login": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SubscriptionLogin"
              },
              {
                "type": "null"
              }
            ],
            "description": "A sign-in in progress."
          },
          "provider": {
            "description": "claude | chatgpt",
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "agent",
          "connected",
          "provider",
          "title"
        ],
        "type": "object"
      },
      "SubscriptionCode": {
        "properties": {
          "code": {
            "type": "string"
          }
        },
        "required": [
          "code"
        ],
        "type": "object"
      },
      "SubscriptionLogin": {
        "description": "A sign-in in progress: open `url`, then (Claude) paste the code shown back with `POST …/login/code`, or (ChatGPT) enter `user_code` on that page.",
        "properties": {
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "needs_code": {
            "description": "Paste the code the vendor's page shows into `POST …/login/code`.",
            "type": "boolean"
          },
          "provider": {
            "type": "string"
          },
          "sandbox": {
            "description": "The sandbox the vendor's own CLI runs the sign-in in.",
            "type": "string"
          },
          "started_at": {
            "format": "int64",
            "type": "integer"
          },
          "status": {
            "description": "starting | waiting_for_user | connected | failed",
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          },
          "user_code": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "needs_code",
          "provider",
          "sandbox",
          "started_at",
          "status"
        ],
        "type": "object"
      },
      "Telemetry": {
        "description": "`GET /telemetry`: the account's OpenTelemetry endpoint (header values are never returned).",
        "properties": {
          "endpoint": {
            "type": "string"
          },
          "headers": {
            "description": "Header names only.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_export_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "endpoint",
          "headers"
        ],
        "type": "object"
      },
      "TelemetrySaved": {
        "properties": {
          "telemetry": {
            "$ref": "#/components/schemas/Telemetry"
          },
          "test": {
            "$ref": "#/components/schemas/TelemetryTest"
          }
        },
        "required": [
          "telemetry",
          "test"
        ],
        "type": "object"
      },
      "TelemetryTest": {
        "description": "The collector's answer to the test export sent on save.",
        "properties": {
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "ok": {
            "type": "boolean"
          },
          "status": {
            "format": "uint16",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "ok"
        ],
        "type": "object"
      },
      "Trial": {
        "properties": {
          "active": {
            "description": "In the trial now. Before choosing a plan this is false and `ends_at` None: the trial starts with the first plan.",
            "type": "boolean"
          },
          "blocked": {
            "description": "The card already had a free trial on another account (`trial_blocked`): the plan is paid from the start.",
            "type": "boolean"
          },
          "days": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "ends_at": {
            "description": "Unix seconds; None until the trial starts.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "hours": {
            "default": 0,
            "description": "Hours of running time the trial includes (all sandboxes together).",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "hours_used": {
            "default": 0.0,
            "description": "Hours used so far.",
            "format": "double",
            "type": "number"
          },
          "max_auto_stop_secs": {
            "default": 0,
            "description": "The longest auto-stop timer during the trial, in seconds (also its default): the trial needs one (`trial_auto_stop_required`). It can't save new saved snapshots either.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "max_sandboxes": {
            "description": "Sandboxes at once during the trial.",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "active",
          "days",
          "max_sandboxes"
        ],
        "type": "object"
      },
      "UpdateAiProfile": {
        "properties": {
          "default": {
            "description": "true: make it the account's default profile.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "name": {
            "description": "Rename.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateAiProxy": {
        "description": "Change the proxy settings (`PUT /v1/ai/proxy`); fields left out stay.",
        "properties": {
          "blocked": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "enabled": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "withhold_subscriptions": {
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateAlertSettings": {
        "description": "`PATCH /v1/account/alerts`: `{\"emails\": {\"plan_nudge\": false}, \"auto_rebuild\": true}`; kinds left out stay as they are.",
        "properties": {
          "auto_rebuild": {
            "default": null,
            "type": [
              "boolean",
              "null"
            ]
          },
          "emails": {
            "additionalProperties": {
              "type": "boolean"
            },
            "default": {},
            "type": "object"
          }
        },
        "type": "object"
      },
      "UpdateDataRetention": {
        "properties": {
          "confirmation": {
            "description": "Turning zero data retention on erases the data of every stopped sandbox: send \"delete stopped sandbox data\" to confirm.",
            "type": [
              "string",
              "null"
            ]
          },
          "monitoring_off": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "snapshots_off": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "zero_data_retention": {
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateEnvironment": {
        "description": "`PATCH /environment`: fields left out stay as they are; `setup: \"\"` removes the script.",
        "properties": {
          "default": {
            "description": "true: make it the default (the one new sandboxes use when they name none).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "name": {
            "description": "Rename it (sandboxes stay on their versions).",
            "type": [
              "string",
              "null"
            ]
          },
          "repo_setup": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Setup scripts per repo directory; `\"\"` removes one. Scripts not named stay.",
            "type": [
              "object",
              "null"
            ]
          },
          "repos": {
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "setup": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateInbox": {
        "description": "`PATCH /v1/inboxes/{inbox}`: rename it, or attach it to a sandbox (`\"\"` detaches it).",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "sandbox": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateSandbox": {
        "description": "`PATCH /sandboxes/{name}`: rename, change the auto-stop timer, or change labels.",
        "properties": {
          "auto_start": {
            "description": "true: while stopped, a request to one of its public URLs, or an exec, file, job or wait call, starts it; false: off.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "delete_after_secs": {
            "description": "Delete it after staying stopped this many seconds (0 = never).",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "expires_in_secs": {
            "description": "Delete it this many seconds from now, running or not (60 s to 365 days); 0 removes the deadline.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "labels": {
            "additionalProperties": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Labels to set; a null value removes that label. Labels not named stay.",
            "type": [
              "object",
              "null"
            ]
          },
          "max_lifetime_secs": {
            "description": "Stop it this many seconds after each start (0 = no limit). Set while it runs, it counts from that start.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "ttl_secs": {
            "description": "A new auto-stop timer in seconds (0 = no auto-stop). While running, the sandbox then stops this long from now (`froog extend --hours`); later starts use it too.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateSandboxAi": {
        "description": "Change a sandbox's AI settings (`PUT /v1/sandboxes/{name}/ai`).",
        "properties": {
          "blocked": {
            "description": "Refuse (true) or accept again (false) its AI requests, at once. Blocking needs `sandbox.update`; unblocking needs `environment.write` or `account.admin` on a key not limited to some sandboxes (never the in-sandbox key), and an owner or admin in an organization.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "profile": {
            "description": "A profile name or id; \"\" (empty) goes back to its environment's. Proxied requests use it at once; the variables the sandbox gets change at its next start. Changing it needs what unblocking needs.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateWebhook": {
        "description": "`PATCH /webhooks/{id}`: change what's given. The signing secret stays (rotate changes it).",
        "properties": {
          "enabled": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "events": {
            "description": "Empty = every event.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "name": {
            "description": "An empty name removes it.",
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpgradeEnvironment": {
        "description": "Optional body of `POST /environments/{env}/upgrade`.",
        "properties": {
          "sandboxes": {
            "description": "Only these sandboxes (names). Default: every sandbox of the environment on an older version.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UrlToken": {
        "description": "A viewer token of a private URL (`GET /sandboxes/{name}/urls/{port}/tokens`).",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "expires_at": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "description": "`utk_…`, for revoking it.",
            "type": "string"
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "token": {
            "description": "Only when created: the secret (`pvt_…`). Send it as `?_token=` (the proxy turns it into a cookie) or in the `X-Froog-Url-Token` header.",
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "description": "Only when created: the URL with `?_token=` for this token.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "created_at",
          "expires_at",
          "id"
        ],
        "type": "object"
      },
      "Usage": {
        "properties": {
          "billable_usd": {
            "description": "Usage past the plan, taken from the wallet.",
            "format": "double",
            "type": "number"
          },
          "free_trial_until": {
            "description": "The period is the free trial: nothing is charged before this time (unix seconds).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "from": {
            "default": 0,
            "description": "The period, unix seconds: the current billing period (or the trial), or the calendar month asked for. `to` is now for a period still running.",
            "format": "int64",
            "type": "integer"
          },
          "included_usd": {
            "default": 0.0,
            "description": "What the plan paid for this period covers.",
            "format": "double",
            "type": "number"
          },
          "lines": {
            "items": {
              "$ref": "#/components/schemas/UsageLine"
            },
            "type": "array"
          },
          "month": {
            "description": "\"YYYY-MM\" of the period's start.",
            "type": "string"
          },
          "saved_snapshot_days": {
            "format": "double",
            "type": "number"
          },
          "snapshot_cost_usd": {
            "format": "double",
            "type": "number"
          },
          "to": {
            "default": 0,
            "format": "int64",
            "type": "integer"
          },
          "total_usd": {
            "description": "Everything used in the period, at list prices.",
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "billable_usd",
          "lines",
          "month",
          "saved_snapshot_days",
          "snapshot_cost_usd",
          "total_usd"
        ],
        "type": "object"
      },
      "UsageLine": {
        "properties": {
          "backend": {
            "description": "`froog`: a sandbox's running time. `ci`: CI job time (`runs-on: froog`), priced per vCPU minute.",
            "type": "string"
          },
          "cost_usd": {
            "format": "double",
            "type": "number"
          },
          "seconds": {
            "description": "Running time (or CI job time) in the period, billed per second.",
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "size": {
            "$ref": "#/components/schemas/Size"
          }
        },
        "required": [
          "backend",
          "cost_usd",
          "seconds",
          "size"
        ],
        "type": "object"
      },
      "WaitForPort": {
        "description": "`POST /sandboxes/{name}/wait`: wait until something listens on a TCP port inside the sandbox.",
        "properties": {
          "port": {
            "format": "uint16",
            "minimum": 0.0,
            "type": "integer"
          },
          "timeout_secs": {
            "description": "Give up after this many seconds (1-600, default 60). Time spent starting counts.",
            "format": "uint64",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "port"
        ],
        "type": "object"
      },
      "Waitlist": {
        "properties": {
          "email": {
            "type": "string"
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "email"
        ],
        "type": "object"
      },
      "WalletBonus": {
        "description": "The wallet bonus: none below `from_usd`; from `from_percent` there, growing evenly on a log scale to `to_percent` at `to_usd`, and `to_percent` above that.",
        "properties": {
          "examples": {
            "description": "What some amounts get.",
            "items": {
              "$ref": "#/components/schemas/WalletQuote"
            },
            "type": "array"
          },
          "from_percent": {
            "format": "double",
            "type": "number"
          },
          "from_usd": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "to_percent": {
            "format": "double",
            "type": "number"
          },
          "to_usd": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "examples",
          "from_percent",
          "from_usd",
          "to_percent",
          "to_usd"
        ],
        "type": "object"
      },
      "WalletPay": {
        "description": "`POST /v1/billing/wallet/pay`: charge the saved card and add the money to the wallet.",
        "properties": {
          "amount_usd": {
            "description": "Whole dollars, from `Billing.min_topup_usd` to `Billing.max_wallet_per_day_usd` (also the most charged in any 24 hours).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          }
        },
        "required": [
          "amount_usd"
        ],
        "type": "object"
      },
      "WalletQuote": {
        "description": "`GET /v1/billing/wallet/quote?amount_usd=N`: what a payment of N dollars puts in the wallet.",
        "properties": {
          "amount_usd": {
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "bonus_percent": {
            "format": "double",
            "type": "number"
          },
          "bonus_usd": {
            "format": "double",
            "type": "number"
          },
          "credited_usd": {
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "amount_usd",
          "bonus_percent",
          "bonus_usd",
          "credited_usd"
        ],
        "type": "object"
      },
      "Webhook": {
        "description": "A webhook endpoint (the signing secret is shown only when created or rotated).",
        "properties": {
          "created_at": {
            "format": "int64",
            "type": "integer"
          },
          "enabled": {
            "default": true,
            "description": "false: paused, nothing is sent (test pings still are).",
            "type": "boolean"
          },
          "events": {
            "description": "Empty = every event.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "id": {
            "type": "string"
          },
          "name": {
            "description": "Your own name for it (up to 100 characters).",
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "events",
          "id",
          "url"
        ],
        "type": "object"
      },
      "WebhookDelivery": {
        "description": "One delivery attempt of a webhook (`GET /webhooks/{id}/deliveries`, kept 30 days).",
        "properties": {
          "attempt": {
            "description": "1-8 (`froog-attempt`).",
            "format": "uint32",
            "minimum": 0.0,
            "type": "integer"
          },
          "created_at": {
            "description": "Unix seconds.",
            "format": "int64",
            "type": "integer"
          },
          "duration_ms": {
            "format": "uint64",
            "minimum": 0.0,
            "type": "integer"
          },
          "error": {
            "description": "What went wrong (a connection error, a non-2xx answer).",
            "type": [
              "string",
              "null"
            ]
          },
          "event": {
            "description": "sandbox.running, …, or ping.",
            "type": "string"
          },
          "event_id": {
            "description": "The event id (`evt_…`, also the `froog-delivery` header): the same on every attempt.",
            "type": "string"
          },
          "next_attempt_at": {
            "description": "When the next attempt is due, if one is.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "response_code": {
            "description": "The endpoint's HTTP status; none when it couldn't be reached.",
            "format": "uint16",
            "minimum": 0.0,
            "type": [
              "integer",
              "null"
            ]
          },
          "sandbox": {
            "description": "The sandbox it was about (none for a ping).",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "description": "delivered | failed (another attempt follows unless this was the last).",
            "type": "string"
          }
        },
        "required": [
          "attempt",
          "created_at",
          "duration_ms",
          "event",
          "event_id",
          "status"
        ],
        "type": "object"
      },
      "WebhookSecret": {
        "properties": {
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "secret": {
            "description": "Verify `froog-signature` with this; shown once.",
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "events",
          "id",
          "secret",
          "url"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearer": {
        "description": "An API key (froog_…) from the dashboard or `froog api-key create`",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "Cloud sandboxes for AI agents: full Linux VMs you create, run commands in, snapshot, fork and stop. Authenticate with an API key as a bearer token. Each account may send 10,000 requests per 60 s; requests without a valid key count per client IP (RateLimit-* headers on every answer; past it, 429 account_rate_limited or ip_rate_limited with Retry-After). Docs: https://froogcorp.com/docs/",
    "title": "froog API",
    "version": "0.12.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/mcp": {
      "post": {
        "operationId": "mcp",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "MCP server (Streamable HTTP, stateless): JSON-RPC 2.0 initialize, tools/list and tools/call, with tools to list, create, run commands in, fork, snapshot, stop and delete sandboxes, run background commands and read their output, read and write files and host ports. A scoped key may call only the tools its actions allow. An exec call with _meta.progressToken from a client that accepts text/event-stream is answered as server-sent events (output as notifications/progress, then the result). With FROOG_SERVER_MCP_OAUTH on, a 401 points at OAuth metadata (MCP authorization) and the access tokens are scoped API keys",
        "tags": [
          "MCP"
        ]
      }
    },
    "/v1/account": {
      "get": {
        "operationId": "getAccount",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The signed-in account",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/alerts": {
      "get": {
        "operationId": "getAlertSettings",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertSettings"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Alerts settings: which emails the account gets, and automatic rebuilds",
        "tags": [
          "Account"
        ]
      },
      "patch": {
        "operationId": "updateAlertSettings",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAlertSettings"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertSettings"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Turn kinds of email, or automatic rebuilds, on or off",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/close": {
      "post": {
        "operationId": "closeAccount",
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountClosing"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Close the account: cancel the plan now, stop every sandbox, revoke every key; reopen within 30 days. Needs the header X-Froog-Confirm-Close set to the account's email, and a full-access key or a dashboard session",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/connections": {
      "get": {
        "operationId": "listConnections",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Connection"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Ways to sign in to the account (Google, GitHub, email, AgentID); the primary one's address gets the account's emails",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/connections/email": {
      "post": {
        "operationId": "sendConnectionEmailCode",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailCodeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Send a 6-digit code to an address to add it as a sign-in connection",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/connections/email/verify": {
      "post": {
        "operationId": "verifyConnectionEmailCode",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailCodeVerify"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Add the address with the code from the email",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/connections/{id}": {
      "delete": {
        "operationId": "removeConnection",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove a sign-in connection (not the last one: 409 last_connection)",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/data-retention": {
      "get": {
        "operationId": "getDataRetention",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataRetention"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Data controls: zero data retention, snapshots off, monitoring off",
        "tags": [
          "Account"
        ]
      },
      "patch": {
        "operationId": "updateDataRetention",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataRetention"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataRetention"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Change data controls (dashboard session only)",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/primary": {
      "put": {
        "operationId": "setPrimaryConnection",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetPrimary"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Make a connection primary: its address gets the account's emails",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/account/reopen": {
      "post": {
        "operationId": "reopenAccount",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountClosing"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Reopen a closed account within its 30-day window (the plan isn't restored)",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/ai/environments/{env}": {
      "put": {
        "operationId": "setAiEnvironmentProfile",
        "parameters": [
          {
            "in": "path",
            "name": "env",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetAiEnvironmentProfile"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiProfile"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The credential profile an environment's sandboxes get",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/ai/profiles": {
      "get": {
        "operationId": "listAiProfiles",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/AiProfile"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Credential profiles and their accounts (never the keys)",
        "tags": [
          "AI credentials"
        ]
      },
      "post": {
        "operationId": "createAiProfile",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAiProfile"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiProfile"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Create a credential profile, empty or as a copy",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/ai/profiles/{profile}": {
      "delete": {
        "operationId": "deleteAiProfile",
        "parameters": [
          {
            "in": "path",
            "name": "profile",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete a profile (not the default, not one an environment uses)",
        "tags": [
          "AI credentials"
        ]
      },
      "get": {
        "operationId": "getAiProfile",
        "parameters": [
          {
            "in": "path",
            "name": "profile",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiProfile"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One credential profile (name or id)",
        "tags": [
          "AI credentials"
        ]
      },
      "patch": {
        "operationId": "updateAiProfile",
        "parameters": [
          {
            "in": "path",
            "name": "profile",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAiProfile"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiProfile"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Rename a profile, or make it the default",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/ai/profiles/{profile}/credentials": {
      "post": {
        "operationId": "addAiCredential",
        "parameters": [
          {
            "in": "path",
            "name": "profile",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddAiCredential"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCredential"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Add a provider key or custom API to a profile (another account when the provider has one)",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/ai/profiles/{profile}/credentials/{id}": {
      "delete": {
        "operationId": "removeAiCredential",
        "parameters": [
          {
            "in": "path",
            "name": "profile",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove a key from a profile",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/ai/profiles/{profile}/credentials/{id}/active": {
      "put": {
        "operationId": "switchAiCredential",
        "parameters": [
          {
            "in": "path",
            "name": "profile",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiProfile"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Use this account first for its provider",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/ai/proxy": {
      "get": {
        "operationId": "getAiProxy",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiProxy"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The AI proxy: on or off, blocked, subscriptions withheld, its URL",
        "tags": [
          "AI credentials"
        ]
      },
      "put": {
        "operationId": "updateAiProxy",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAiProxy"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiProxy"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Turn the AI proxy on or off (sandboxes switch at their next start), block every proxied sandbox",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/ai/usage": {
      "get": {
        "operationId": "getAiUsage",
        "parameters": [
          {
            "description": "1-366 UTC days, default 30",
            "in": "query",
            "name": "days",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiUsage"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Proxied AI usage per sandbox: requests, tokens, estimated cost",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/api-keys": {
      "get": {
        "operationId": "listApiKeys",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ApiKeyInfo"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "API keys (secrets are never returned)",
        "tags": [
          "Keys"
        ]
      },
      "post": {
        "operationId": "createApiKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewApiKey"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedApiKey"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Create an API key: a preset or actions, sandboxes or labels, expiry",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/api-keys/{id}": {
      "delete": {
        "operationId": "revokeApiKey",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Revoke an API key",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/api-keys/{id}/rotate": {
      "post": {
        "operationId": "rotateApiKey",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedApiKey"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A new secret for a key (same id, scope and expiry)",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/audit": {
      "get": {
        "operationId": "listAuditEvents",
        "parameters": [
          {
            "description": "exact actions, comma-separated (e.g. sandbox.delete,sandbox.auto_stop)",
            "in": "query",
            "name": "action",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "entries about this sandbox",
            "in": "query",
            "name": "sandbox",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds",
            "in": "query",
            "name": "until",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "desc (newest first, the default) or asc",
            "in": "query",
            "name": "sort",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-200, default 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "next_cursor of the previous page",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditList"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The account's audit log, newest first (90 days): who created, deleted or changed what, from which IP",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/audit/export": {
      "get": {
        "operationId": "exportAudit",
        "parameters": [
          {
            "description": "csv (default) or ndjson",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "exact actions, comma-separated",
            "in": "query",
            "name": "action",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "entries about this sandbox",
            "in": "query",
            "name": "sandbox",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds",
            "in": "query",
            "name": "until",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "asc (oldest first, the default) or desc",
            "in": "query",
            "name": "sort",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The file"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Every matching audit entry of the last 90 days as one CSV or NDJSON file",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/billing": {
      "get": {
        "operationId": "getBilling",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Billing"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Plan, rates, this period's usage, wallet and auto top-up",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/billing/extra-starts": {
      "put": {
        "operationId": "setExtraStarts",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetExtraStarts"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Billing"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Turn extra starts on or off: starts past the start limits paid from the wallet",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/billing/plan": {
      "delete": {
        "operationId": "cancelPlan",
        "parameters": [
          {
            "description": "true: pause instead. When the plan ends every sandbox stops, and stopped disks and saved snapshots are kept free for 90 days",
            "in": "query",
            "name": "keep_disks",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Billing"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Cancel the plan at the end of the period",
        "tags": [
          "Account"
        ]
      },
      "post": {
        "operationId": "choosePlan",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChoosePlan"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlanChange"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Choose or change the plan (the first one returns a Stripe Checkout page)",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/billing/portal": {
      "post": {
        "operationId": "billingPortal",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingUrl"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A Stripe page to change the card and download invoices",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/billing/trial/end": {
      "post": {
        "operationId": "endTrial",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Billing"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "End the free trial now and start the plan",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/billing/wallet/auto-topup": {
      "put": {
        "operationId": "setAutoTopup",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AutoTopup"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Billing"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Set auto top-up (0 = off)",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/billing/wallet/pay": {
      "post": {
        "operationId": "walletPay",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WalletPay"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Billing"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Charge the saved card and add the money to the wallet",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/billing/wallet/quote": {
      "get": {
        "operationId": "walletQuote",
        "parameters": [
          {
            "description": "whole dollars",
            "in": "query",
            "name": "amount_usd",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletQuote"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "What a wallet payment adds, with its bonus",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/ci": {
      "get": {
        "operationId": "getCiOverview",
        "parameters": [
          {
            "description": "owner/name",
            "in": "query",
            "name": "repo",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "all (default), active or failed",
            "in": "query",
            "name": "state",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-200, default 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiOverview"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "CI on froog: setup, 7-day stats and the last GitHub Actions jobs (runs-on: froog)",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/analytics": {
      "get": {
        "operationId": "getCiAnalytics",
        "parameters": [
          {
            "description": "1-30, default 7",
            "in": "query",
            "name": "days",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "owner/name",
            "in": "query",
            "name": "repo",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiAnalytics"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "CI analytics: per repository and job, runs, failure rate, p50/p90 duration and wait, cost, CPU and memory, a size advice, and flaky tests",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/jobs/{id}": {
      "get": {
        "operationId": "getCiJob",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiJob"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One CI job: state, reason, wait, run time and sandbox",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/jobs/{id}/logs": {
      "get": {
        "operationId": "getCiJobLog",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The file"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One CI job's log from GitHub (text, the last 1 MiB)",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/jobs/{id}/metrics": {
      "get": {
        "operationId": "getCiJobMetrics",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiJobMetrics"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One CI job's CPU and memory over time, and its steps with their times",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/jobs/{id}/tests": {
      "get": {
        "operationId": "getCiJobTests",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiJobTests"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One CI job's test results, from the JUnit XML files it wrote (failed first)",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/logs/search": {
      "get": {
        "operationId": "searchCiLogs",
        "parameters": [
          {
            "description": "words, \"phrases\", -excluded, repo: branch: workflow: job: conclusion: step: level:error|warning",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-30, default 7",
            "in": "query",
            "name": "days",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-500, default 100",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "newest (default) or oldest",
            "in": "query",
            "name": "order",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiLogSearch"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Search the kept logs of finished CI jobs, line by line",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/monitors": {
      "get": {
        "operationId": "listCiMonitors",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/CiMonitor"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "CI monitors: alerts when matching jobs fail or run long, with their last alerts",
        "tags": [
          "Integrations"
        ]
      },
      "post": {
        "operationId": "createCiMonitor",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCiMonitor"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiMonitor"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Add a CI monitor (email and the ci.monitor.triggered webhook event)",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/monitors/{id}": {
      "delete": {
        "operationId": "deleteCiMonitor",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove a CI monitor",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/runs": {
      "get": {
        "operationId": "listCiRuns",
        "parameters": [
          {
            "description": "owner/name",
            "in": "query",
            "name": "repo",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "all (default), active or failed",
            "in": "query",
            "name": "state",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "workflow name",
            "in": "query",
            "name": "workflow",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "branch",
            "in": "query",
            "name": "branch",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "words in the title, job names, workflow, repository, branch, commit or actor",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-100, default 25",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "runs to skip",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiRunList"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "CI workflow runs, newest first, a page at a time: each run's GitHub title, event, number, actor and its jobs on froog, plus the total and the workflows, repositories and branches to filter by",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/runs/{run_id}": {
      "get": {
        "operationId": "getCiRun",
        "parameters": [
          {
            "in": "path",
            "name": "run_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiRun"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One CI workflow run (GitHub's run id) and its jobs on froog",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/ci/settings": {
      "put": {
        "operationId": "setCiSettings",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CiSettings"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CiSettings"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Let jobs from public repositories run, optionally only for listed GitHub users",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/cli-login": {
      "post": {
        "operationId": "startCliLogin",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CliLoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliLoginStarted"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "security": [],
        "summary": "Start a browser login for the CLI",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/cli-login/poll": {
      "post": {
        "operationId": "pollCliLogin",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CliLoginPoll"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliLoginResult"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "security": [],
        "summary": "Poll a CLI login (202 until approved)",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/cli-login/{code}": {
      "delete": {
        "operationId": "denyCliLogin",
        "parameters": [
          {
            "in": "path",
            "name": "code",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Deny a CLI login",
        "tags": [
          "Keys"
        ]
      },
      "get": {
        "operationId": "getCliLogin",
        "parameters": [
          {
            "in": "path",
            "name": "code",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliLoginInfo"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Describe a pending CLI login",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/cli-login/{code}/approve": {
      "post": {
        "operationId": "approveCliLogin",
        "parameters": [
          {
            "in": "path",
            "name": "code",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Approve a CLI login (creates a key)",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/dashboard-link": {
      "post": {
        "operationId": "createDashboardLink",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardLink"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A link that opens the dashboard signed in: single use, 15 minutes (full-access keys and sessions only)",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/deletion-operations/{id}": {
      "get": {
        "operationId": "getDeletionOperation",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeletionOperation"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A deletion operation (dop_…): an account close or a zero data retention erasure",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/env": {
      "get": {
        "operationId": "listEnv",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/EnvVar"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Account environment variables (names and previews)",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/env/{name}": {
      "delete": {
        "operationId": "removeEnv",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove an account environment variable",
        "tags": [
          "Environment"
        ]
      },
      "put": {
        "operationId": "setEnv",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetEnvVar"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Set an account environment variable",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/environment": {
      "get": {
        "operationId": "getEnvironment",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Environment"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Repos, secret files and setup script every new sandbox gets",
        "tags": [
          "Environment"
        ]
      },
      "patch": {
        "operationId": "updateEnvironment",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEnvironment"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Environment"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Change repos or the setup script",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/environment/files": {
      "delete": {
        "operationId": "removeEnvironmentFile",
        "parameters": [
          {
            "description": "the file, relative to ~",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove a secret file",
        "tags": [
          "Environment"
        ]
      },
      "put": {
        "operationId": "setEnvironmentFile",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetEnvFile"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Write a secret file",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/environments": {
      "get": {
        "operationId": "listEnvironments",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/EnvironmentSummary"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Named environments: default marker, latest version, sandboxes per version",
        "tags": [
          "Environment"
        ]
      },
      "post": {
        "operationId": "createEnvironment",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewEnvironment"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Environment"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Create an environment (empty, or a copy of another's latest version)",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/environments/{env}": {
      "delete": {
        "operationId": "deleteEnvironment",
        "parameters": [
          {
            "in": "path",
            "name": "env",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete an environment (its sandboxes keep their version; not the default)",
        "tags": [
          "Environment"
        ]
      },
      "get": {
        "operationId": "getNamedEnvironment",
        "parameters": [
          {
            "in": "path",
            "name": "env",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Environment"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One environment: repos, setup scripts, secret files (names and sizes), latest version",
        "tags": [
          "Environment"
        ]
      },
      "patch": {
        "operationId": "updateNamedEnvironment",
        "parameters": [
          {
            "in": "path",
            "name": "env",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEnvironment"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Environment"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Change repos or setup scripts (a new version), rename, or make it the default",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/environments/{env}/files": {
      "delete": {
        "operationId": "removeNamedEnvironmentFile",
        "parameters": [
          {
            "in": "path",
            "name": "env",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "the file, relative to ~",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove a secret file (a new version)",
        "tags": [
          "Environment"
        ]
      },
      "put": {
        "operationId": "setNamedEnvironmentFile",
        "parameters": [
          {
            "in": "path",
            "name": "env",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetEnvFile"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Write a secret file (a new version)",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/environments/{env}/upgrade": {
      "post": {
        "operationId": "upgradeEnvironment",
        "parameters": [
          {
            "in": "path",
            "name": "env",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpgradeEnvironment"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvironmentUpgrade"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Move its sandboxes to the latest version (running ones now, stopped ones at their next start)",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/environments/{env}/versions": {
      "get": {
        "operationId": "listEnvironmentVersions",
        "parameters": [
          {
            "in": "path",
            "name": "env",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/EnvironmentVersion"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "An environment's versions, newest first, with sandboxes on each",
        "tags": [
          "Environment"
        ]
      }
    },
    "/v1/feedback": {
      "post": {
        "operationId": "sendFeedback",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Feedback"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Send feedback to the froog team",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/file-urls/{token}": {
      "get": {
        "operationId": "downloadSigned",
        "parameters": [
          {
            "in": "path",
            "name": "token",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The file"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "security": [],
        "summary": "Download through a signed link",
        "tags": [
          "Files"
        ]
      },
      "put": {
        "operationId": "uploadSigned",
        "parameters": [
          {
            "in": "path",
            "name": "token",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/octet-stream": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "security": [],
        "summary": "Upload through a signed link (raw bytes)",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/github": {
      "get": {
        "operationId": "getGithub",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GithubStatus"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The GitHub connection: linked installations and the repositories the sandbox token is limited to",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/github/connect": {
      "post": {
        "operationId": "connectGithub",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GithubConnect"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A link that installs the froog GitHub App on a GitHub account or organization",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/github/installations/{id}": {
      "delete": {
        "operationId": "disconnectGithubInstallation",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Unlink a GitHub installation from the account",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/github/repos": {
      "get": {
        "operationId": "listGithubRepos",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/GithubRepo"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Repositories the linked installations can see",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/github/token-repos": {
      "put": {
        "operationId": "setGithubTokenRepos",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetTokenRepos"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GithubStatus"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Limit the GitHub token in each sandbox to these repositories (empty: all the app can see)",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/images": {
      "get": {
        "operationId": "listImages",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/OsImage"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Operating systems a sandbox can run",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/inboxes": {
      "get": {
        "operationId": "listInboxes",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Inbox"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Your agent inboxes",
        "tags": [
          "Inboxes"
        ]
      },
      "post": {
        "operationId": "createInbox",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInbox"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Inbox"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Make an inbox ($2 a month): an email address that receives mail for an agent. Uses a paid seat, or adds one; 402 inbox_payment_required without an inbox subscription",
        "tags": [
          "Inboxes"
        ]
      }
    },
    "/v1/inboxes/billing": {
      "get": {
        "operationId": "getInboxBilling",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxBilling"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "What you pay for inboxes: seats paid for, inboxes used, the subscription's status",
        "tags": [
          "Inboxes"
        ]
      }
    },
    "/v1/inboxes/billing/checkout": {
      "post": {
        "operationId": "buyInboxes",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InboxCheckout"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingUrl"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A Stripe Checkout page that buys inboxes (default: yours plus one)",
        "tags": [
          "Inboxes"
        ]
      }
    },
    "/v1/inboxes/{inbox}": {
      "delete": {
        "operationId": "deleteInbox",
        "parameters": [
          {
            "in": "path",
            "name": "inbox",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete an inbox and its messages (the address is never given out again; its seat stays paid until the period ends)",
        "tags": [
          "Inboxes"
        ]
      },
      "get": {
        "operationId": "getInbox",
        "parameters": [
          {
            "in": "path",
            "name": "inbox",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Inbox"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One inbox (by id, address, or the part before @)",
        "tags": [
          "Inboxes"
        ]
      },
      "patch": {
        "operationId": "updateInbox",
        "parameters": [
          {
            "in": "path",
            "name": "inbox",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateInbox"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Inbox"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Rename an inbox, or attach it to a sandbox (\"\" detaches it)",
        "tags": [
          "Inboxes"
        ]
      }
    },
    "/v1/inboxes/{inbox}/messages": {
      "get": {
        "operationId": "listInboxMessages",
        "parameters": [
          {
            "in": "path",
            "name": "inbox",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds: only messages received at or after",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "default 50, at most 100",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxMessageList"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Received messages, newest first, without their bodies",
        "tags": [
          "Inboxes"
        ]
      }
    },
    "/v1/inboxes/{inbox}/messages/{id}": {
      "delete": {
        "operationId": "deleteInboxMessage",
        "parameters": [
          {
            "in": "path",
            "name": "inbox",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete a message",
        "tags": [
          "Inboxes"
        ]
      },
      "get": {
        "operationId": "getInboxMessage",
        "parameters": [
          {
            "in": "path",
            "name": "inbox",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxMessage"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One message with its text, HTML, codes and links",
        "tags": [
          "Inboxes"
        ]
      }
    },
    "/v1/inboxes/{inbox}/messages/{id}/raw": {
      "get": {
        "operationId": "getInboxMessageRaw",
        "parameters": [
          {
            "in": "path",
            "name": "inbox",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The file"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The message as received (message/rfc822)",
        "tags": [
          "Inboxes"
        ]
      }
    },
    "/v1/inboxes/{inbox}/wait": {
      "get": {
        "operationId": "waitForInboxMessage",
        "parameters": [
          {
            "in": "path",
            "name": "inbox",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds: only messages received at or after (default: 60 seconds ago)",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "a message id: only messages that arrived after it",
            "in": "query",
            "name": "after",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "part of the From address or name",
            "in": "query",
            "name": "sender",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "part of the subject",
            "in": "query",
            "name": "subject",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "seconds to wait, default 60, at most 120",
            "in": "query",
            "name": "timeout",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxWait"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Wait for the next message (its one-time codes and verification links already pulled out); message is null on timeout",
        "tags": [
          "Inboxes"
        ]
      }
    },
    "/v1/limits": {
      "get": {
        "operationId": "getLimits",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Limits"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "What the account can run now: sandboxes at once, sizes, trial, start limits",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/provider-models": {
      "get": {
        "operationId": "providerModels",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ProviderModels"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "security": [],
        "summary": "The harnesses, their models, effort levels and fast mode",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes": {
      "get": {
        "operationId": "listSandboxes",
        "parameters": [
          {
            "description": "key=value, or key for any value; repeat to require several",
            "explode": true,
            "in": "query",
            "name": "label",
            "required": false,
            "schema": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "style": "form"
          },
          {
            "description": "exact name",
            "in": "query",
            "name": "name",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "names that start with this",
            "in": "query",
            "name": "name_prefix",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "creating, starting, running, stopping, stopped, restoring, deleting or error; comma-separated for several",
            "in": "query",
            "name": "state",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "asc (oldest first, the default) or desc (newest first)",
            "in": "query",
            "name": "sort",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-200; without it, every match. With it, X-Next-Cursor names the next page",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "X-Next-Cursor of the previous page (it is `<created_at>_<id>` of that page's last sandbox)",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Sandbox"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK",
            "headers": {
              "X-Next-Cursor": {
                "description": "With limit, when more follow: pass it as cursor",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Sandboxes, oldest first, filtered and paged",
        "tags": [
          "Sandboxes"
        ]
      },
      "post": {
        "operationId": "createSandboxes",
        "parameters": [
          {
            "description": "Any unique string (up to 255 characters). A retry with the same key within 24 hours returns the first response instead of creating more sandboxes; the same key with a different request is a 422 idempotency_key_reused.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSandbox"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Sandbox"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Create sandboxes (202; poll until running)",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}": {
      "delete": {
        "operationId": "deleteSandbox",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete a sandbox (saved snapshots stay)",
        "tags": [
          "Sandboxes"
        ]
      },
      "get": {
        "operationId": "getSandbox",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sandbox"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One sandbox",
        "tags": [
          "Sandboxes"
        ]
      },
      "patch": {
        "operationId": "updateSandbox",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSandbox"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sandbox"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Rename; change the auto-stop timer (counting from now while running), lifetime, auto-delete, auto-start or labels",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/ai": {
      "get": {
        "operationId": "getSandboxAi",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-366 UTC days, default 30",
            "in": "query",
            "name": "days",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxAi"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A sandbox's AI profile, proxy state, block, and usage per day and model",
        "tags": [
          "AI credentials"
        ]
      },
      "put": {
        "operationId": "updateSandboxAi",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSandboxAi"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxAi"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Block or unblock a sandbox's AI requests, or give it another profile",
        "tags": [
          "AI credentials"
        ]
      }
    },
    "/v1/sandboxes/{name}/browser": {
      "post": {
        "operationId": "getBrowserLink",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "dark (default) or light: the viewer's look",
            "in": "query",
            "name": "theme",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrowserRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesktopLink"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A link to the browser view: only Chrome, 1920x1080",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/command-history": {
      "get": {
        "operationId": "listCommands",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "commands (default) | process | sync | stream | detached",
            "in": "query",
            "name": "mode",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "desc (newest first, the default) or asc",
            "in": "query",
            "name": "sort",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-200, default 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "next_cursor of the previous page",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommandList"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Commands run in the sandbox, newest first (90 days, also while stopped)",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/command-history/{id}": {
      "get": {
        "operationId": "getCommand",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommandRecord"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One command's record",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/command-history/{id}/logs": {
      "get": {
        "operationId": "readCommandLogs",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "stdout (default) | stderr",
            "in": "query",
            "name": "stream",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "byte offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "utf8 (default) | base64",
            "in": "query",
            "name": "encoding",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommandLogs"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A command's stored output from an offset (at most 1 MiB)",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/conversations": {
      "get": {
        "operationId": "listConversations",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationList"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Conversations, most recent first",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/conversations/{id}": {
      "delete": {
        "operationId": "deleteConversation",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete a conversation and its history",
        "tags": [
          "Agents"
        ]
      },
      "get": {
        "operationId": "getConversation",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationDetail"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A conversation and its turns (id or current)",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/desktop": {
      "post": {
        "operationId": "getDesktopLink",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "dark (default) or light: the desktop's and the viewer's look",
            "in": "query",
            "name": "theme",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesktopLink"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A link to the desktop (1920x1080) in froog's viewer",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/events": {
      "get": {
        "operationId": "listEvents",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "only this conversation (or current)",
            "in": "query",
            "name": "conversation",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "id of the last event seen",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-1000, default 100 (JSON pages)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventList"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/AgentEvent"
                }
              },
              "text/event-stream": {
                "schema": {
                  "description": "Server-sent events: event = the event type, data = the AgentEvent as JSON, id = its id",
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Every conversation's events: a JSON page, or a stream (Accept: text/event-stream or application/x-ndjson)",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/exec": {
      "post": {
        "operationId": "exec",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExecRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExecResult"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ExecEvent"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Run a command and wait for it; with stream: true, NDJSON events as output arrives",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/files": {
      "delete": {
        "operationId": "deleteFile",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "the file or directory",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "true to delete a directory",
            "in": "query",
            "name": "recursive",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete a file or directory",
        "tags": [
          "Files"
        ]
      },
      "get": {
        "operationId": "fileInfo",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "relative to /home/user, or absolute",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileInfo"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A file's details or a directory listing",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/archive": {
      "put": {
        "operationId": "uploadArchive",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "the directory (created if missing)",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/octet-stream": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Unpack a .tar.gz into a directory (raw bytes, up to 100 MiB)",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/content": {
      "get": {
        "operationId": "readFile",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "the file",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The file"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Download a file (raw bytes, up to 100 MiB)",
        "tags": [
          "Files"
        ]
      },
      "put": {
        "operationId": "writeFile",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "the file",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "e.g. 755",
            "in": "query",
            "name": "mode",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/octet-stream": {
              "schema": {
                "format": "binary",
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Upload a file (raw bytes, up to 100 MiB, atomic)",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/download-url": {
      "post": {
        "operationId": "createDownloadUrl",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewFileUrl"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileUrl"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A link that downloads a file without an API key",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/find": {
      "get": {
        "operationId": "findInFiles",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "text, or an extended regex with regex=true",
            "in": "query",
            "name": "pattern",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "default ~",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "true for a regular expression",
            "in": "query",
            "name": "regex",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileFind"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Lines that contain a text",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/mkdir": {
      "post": {
        "operationId": "makeDirectory",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MakeDir"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Create a directory (and parents)",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/move": {
      "post": {
        "operationId": "moveFile",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MoveFile"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Move or rename",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/permissions": {
      "post": {
        "operationId": "setFilePermissions",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FilePermissions"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Change a file's or directory's permissions (chmod)",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/replace": {
      "post": {
        "operationId": "replaceInFiles",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FileReplace"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/FileReplaced"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Replace a text in files, byte for byte",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/search": {
      "get": {
        "operationId": "searchFiles",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "a glob, e.g. *.py",
            "in": "query",
            "name": "pattern",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "where to look, default ~",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileSearch"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Files whose name matches a glob",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/upload-url": {
      "post": {
        "operationId": "createUploadUrl",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewFileUrl"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileUrl"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A link that takes a PUT of a file without an API key",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/files/watch": {
      "get": {
        "operationId": "watchFiles",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "the file or directory to watch, default ~",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "false: only the directory itself (default true)",
            "in": "query",
            "name": "recursive",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-3600, default 3600",
            "in": "query",
            "name": "timeout_secs",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/FileEvent"
                }
              }
            },
            "description": "One event per line while the client listens"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Stream file changes under a path (NDJSON: ready, then create / modify / delete, then end)",
        "tags": [
          "Files"
        ]
      }
    },
    "/v1/sandboxes/{name}/fork": {
      "post": {
        "operationId": "forkSandbox",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Any unique string (up to 255 characters). A retry with the same key within 24 hours returns the first response instead of creating more sandboxes; the same key with a different request is a 422 idempotency_key_reused.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForkSandbox"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Sandbox"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "New sandboxes from a snapshot of this one",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/github-token": {
      "post": {
        "operationId": "getSandboxGithubToken",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GithubTokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GithubToken"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A one-hour GitHub token for the sandbox (what its git credential helper uses; needs the environment)",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/interrupt": {
      "post": {
        "operationId": "interrupt",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InterruptRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InterruptResult"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Stop running turns and cancel queued prompts (one conversation, or all)",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/jobs": {
      "get": {
        "operationId": "listJobs",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Job"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Background commands",
        "tags": [
          "Commands"
        ]
      },
      "post": {
        "operationId": "startJob",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewJob"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Start a background command",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/jobs/{id}": {
      "get": {
        "operationId": "readJob",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "byte offset to read from",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "bytes to read",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobOutput"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A background command's state and output from an offset",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/jobs/{id}/stdin": {
      "post": {
        "operationId": "writeJobStdin",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JobStdin"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Write to a background command's open standard input (started with stdin_open), or close it",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/jobs/{id}/stop": {
      "post": {
        "operationId": "stopJob",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Stop a background command",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/metrics": {
      "get": {
        "operationId": "getSandboxMetrics",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxMetrics"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "CPU, memory, disk and network of a running sandbox, read now",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/metrics/history": {
      "get": {
        "operationId": "getSandboxMetricsHistory",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds, default an hour ago",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds, default now",
            "in": "query",
            "name": "until",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "seconds per point, default the window / 360 (multiple of 30, at most 1000 points)",
            "in": "query",
            "name": "step",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetricsHistory"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "CPU, memory and disk every 30 seconds, kept 7 days, averaged per step",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/ports": {
      "get": {
        "operationId": "listPorts",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ports"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Inbound ports open on the sandbox (besides SSH), including its public URLs' ports, and the host IPv4 address and port each opened one is reached at",
        "tags": [
          "Ports"
        ]
      },
      "post": {
        "operationId": "openPort",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OpenPort"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ports"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Open an inbound TCP or UDP port: on the sandbox's IPv6 address, and on a public port of its host's IPv4 address",
        "tags": [
          "Ports"
        ]
      },
      "put": {
        "operationId": "setPorts",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetPorts"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ports"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Set the opened ports, replacing the ones opened before (kept across stops and starts)",
        "tags": [
          "Ports"
        ]
      }
    },
    "/v1/sandboxes/{name}/ports/watch": {
      "get": {
        "operationId": "watchPorts",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-3600, default 3600",
            "in": "query",
            "name": "timeout_secs",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/PortEvent"
                }
              }
            },
            "description": "One event per line while the client listens"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Stream TCP ports starting or stopping to listen (NDJSON: ready, open / close, end)",
        "tags": [
          "Ports"
        ]
      }
    },
    "/v1/sandboxes/{name}/ports/{port}/{protocol}": {
      "delete": {
        "operationId": "closePort",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "port",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "protocol",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ports"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Close an opened port (IPv6 and IPv4)",
        "tags": [
          "Ports"
        ]
      }
    },
    "/v1/sandboxes/{name}/processes": {
      "get": {
        "operationId": "listProcesses",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessList"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Processes, busiest first (a stopped sandbox: the sample taken at stop)",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/processes/records": {
      "get": {
        "operationId": "listProcessRecords",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds",
            "in": "query",
            "name": "until",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "true: only processes still running",
            "in": "query",
            "name": "running",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-1000, default 200",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessRecords"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Processes seen in the 30-second samples, with start and end times, kept 72 hours",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/processes/samples": {
      "get": {
        "operationId": "listProcessSamples",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds",
            "in": "query",
            "name": "until",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-1000, default 120",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessSamples"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The 12 busiest processes every 30 seconds, kept 7 days, newest first",
        "tags": [
          "Commands"
        ]
      }
    },
    "/v1/sandboxes/{name}/prompt": {
      "post": {
        "operationId": "prompt",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PromptRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PromptResult"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Prompt a coding agent and wait for its answer (continues the current conversation)",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/prompts": {
      "get": {
        "operationId": "listPrompts",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "only this conversation",
            "in": "query",
            "name": "conversation",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-200, default 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PromptList"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Prompts, newest first",
        "tags": [
          "Agents"
        ]
      },
      "post": {
        "operationId": "queuePrompt",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PromptRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Prompt"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Queue a prompt for a coding agent (returns at once; follow its events)",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/prompts/{id}": {
      "get": {
        "operationId": "getPrompt",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Prompt"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One prompt: status (queued, running, done, failed, interrupted), result, error",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/prompts/{id}/events": {
      "get": {
        "operationId": "promptEvents",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "id of the last event seen",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-1000, default 100 (JSON pages)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventList"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/AgentEvent"
                }
              },
              "text/event-stream": {
                "schema": {
                  "description": "Server-sent events: event = the event type, data = the AgentEvent as JSON, id = its id",
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A prompt's events: a JSON page, or a stream until it ends (Accept: text/event-stream or application/x-ndjson)",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/provider-models": {
      "get": {
        "operationId": "sandboxProviderModels",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ProviderModels"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The model catalog plus the models the harnesses list in this sandbox",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/restore": {
      "post": {
        "operationId": "restoreSandbox",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Restore"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sandbox"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Roll the sandbox back to a snapshot",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/snapshots": {
      "delete": {
        "operationId": "deleteAutoSnapshots",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeletedSnapshots"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete every automatic snapshot (saved ones and the one a stopped sandbox starts from stay)",
        "tags": [
          "Snapshots"
        ]
      },
      "get": {
        "operationId": "listSnapshots",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "asc (oldest first, the default) or desc (newest first)",
            "in": "query",
            "name": "sort",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-200; without it, every one. With it, X-Next-Cursor names the next page",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "X-Next-Cursor of the previous page",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Snapshot"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK",
            "headers": {
              "X-Next-Cursor": {
                "description": "With limit, when more follow: pass it as cursor",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A sandbox's snapshots, oldest first, paged",
        "tags": [
          "Snapshots"
        ]
      },
      "post": {
        "operationId": "saveSnapshot",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSnapshot"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Snapshot"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Save a snapshot (with a label: an account template)",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/sandboxes/{name}/snapshots/{snap}": {
      "delete": {
        "operationId": "deleteSnapshot",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "snap",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delete a snapshot",
        "tags": [
          "Snapshots"
        ]
      },
      "get": {
        "operationId": "getSnapshot",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "snap",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Snapshot"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One snapshot by id or label; latest is the newest available one",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/sandboxes/{name}/snapshots/{snap}/files": {
      "get": {
        "operationId": "snapshotFileInfo",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "snap",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "default ~ (/home/user); relative paths are under it",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileInfo"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A file's details, or a folder's entries, inside a snapshot (the sandbox may be stopped)",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/sandboxes/{name}/snapshots/{snap}/files/download": {
      "get": {
        "operationId": "downloadFromSnapshot",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "snap",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "default ~ (/home/user); relative paths are under it",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The file"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Download a file (raw bytes) or a folder (tar) out of a snapshot",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/sandboxes/{name}/ssh": {
      "get": {
        "operationId": "getSshInfo",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SshInfo"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Where and how to SSH in (host, port, pinned host key)",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/start": {
      "post": {
        "operationId": "startSandbox",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartSandbox"
              }
            }
          },
          "required": false
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sandbox"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Start a stopped sandbox (its auto-stop timer starts again), optionally with a new size, auto-stop timer, environment or env vars",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/steer": {
      "post": {
        "operationId": "steer",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SteerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SteerResult"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Send a message to a running turn (Claude Code takes it mid-turn; others get it as the next turn)",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/sandboxes/{name}/stop": {
      "post": {
        "operationId": "stopSandbox",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StopSandbox"
              }
            }
          },
          "required": false
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sandbox"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Stop: run ~/.froog/pre-stop, snapshot the disk, stop billing (refused and retried if the snapshot fails; force keeps the last good snapshot; the answer's stop_id tracks it)",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/touch": {
      "post": {
        "operationId": "touchSandbox",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Record activity (last_active_at); the auto-stop deadline doesn't move (PATCH ttl_secs does)",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/urls": {
      "get": {
        "operationId": "listUrls",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PublicUrl"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Public URLs of the sandbox's ports",
        "tags": [
          "Public URLs"
        ]
      },
      "post": {
        "operationId": "hostPort",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewPublicUrl"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUrl"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Host a port (private with a token unless public), or rename or title it",
        "tags": [
          "Public URLs"
        ]
      }
    },
    "/v1/sandboxes/{name}/urls/{port}": {
      "delete": {
        "operationId": "removeUrl",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "port",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove a public URL",
        "tags": [
          "Public URLs"
        ]
      }
    },
    "/v1/sandboxes/{name}/urls/{port}/tokens": {
      "get": {
        "operationId": "listUrlTokens",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "port",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/UrlToken"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Live viewer tokens of a private URL (secrets are never returned)",
        "tags": [
          "Public URLs"
        ]
      },
      "post": {
        "operationId": "createUrlToken",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "port",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewUrlToken"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UrlToken"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Another token for a private URL that expires and can be revoked on its own (the secret is returned once)",
        "tags": [
          "Public URLs"
        ]
      }
    },
    "/v1/sandboxes/{name}/urls/{port}/tokens/{id}": {
      "delete": {
        "operationId": "revokeUrlToken",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "port",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Revoke a viewer token",
        "tags": [
          "Public URLs"
        ]
      }
    },
    "/v1/sandboxes/{name}/usage": {
      "get": {
        "operationId": "getSandboxUsage",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds; default the start of the current billing period",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "unix seconds; default now",
            "in": "query",
            "name": "until",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxUsage"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One sandbox's running time and cost in a window, at list prices",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/sandboxes/{name}/wait": {
      "post": {
        "operationId": "waitForPort",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WaitForPort"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortWait"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Wait until something listens on a TCP port inside the sandbox (ready: false after the timeout)",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/saved-snapshots": {
      "get": {
        "operationId": "listSavedSnapshots",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/SavedSnapshot"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Saved snapshots of the account (templates for from)",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/saved-snapshots/{name}": {
      "delete": {
        "operationId": "deleteSavedSnapshot",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove a saved snapshot",
        "tags": [
          "Snapshots"
        ]
      },
      "get": {
        "operationId": "getSavedSnapshot",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedSnapshot"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One saved snapshot and its status",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/saved-snapshots/{name}/files": {
      "get": {
        "operationId": "savedSnapshotFileInfo",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "default ~ (/home/user); relative paths are under it",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileInfo"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A file's details, or a folder's entries, inside a saved snapshot",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/saved-snapshots/{name}/files/download": {
      "get": {
        "operationId": "downloadFromSavedSnapshot",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "default ~ (/home/user); relative paths are under it",
            "in": "query",
            "name": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The file"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Download a file (raw bytes) or a folder (tar) out of a saved snapshot",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/saved-snapshots/{name}/shares": {
      "get": {
        "operationId": "listSnapshotShares",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/SnapshotShare"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A saved snapshot's share codes (not the codes themselves)",
        "tags": [
          "Snapshots"
        ]
      },
      "post": {
        "operationId": "shareSavedSnapshot",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedSnapshotShare"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Make a share code another account can create sandboxes from (shown once)",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/saved-snapshots/{name}/shares/{id}": {
      "delete": {
        "operationId": "revokeSnapshotShare",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Revoke a share code",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/snapshots": {
      "get": {
        "operationId": "listAccountSnapshots",
        "parameters": [
          {
            "description": "desc (newest first, the default) or asc (oldest first)",
            "in": "query",
            "name": "sort",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-200; without it, every one. With it, X-Next-Cursor names the next page",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "X-Next-Cursor of the previous page",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Snapshot"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK",
            "headers": {
              "X-Next-Cursor": {
                "description": "With limit, when more follow: pass it as cursor",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Every snapshot of the account, newest first, with its sandbox, paged",
        "tags": [
          "Snapshots"
        ]
      }
    },
    "/v1/ssh-keys": {
      "get": {
        "operationId": "listSshKeys",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/SshKey"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "SSH public keys that can log in to your sandboxes",
        "tags": [
          "Keys"
        ]
      },
      "post": {
        "operationId": "addSshKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddSshKey"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SshKey"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Add an SSH public key",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/ssh-keys/{id}": {
      "delete": {
        "operationId": "removeSshKey",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove an SSH key",
        "tags": [
          "Keys"
        ]
      }
    },
    "/v1/status": {
      "get": {
        "operationId": "getStatus",
        "responses": {
          "200": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "security": [],
        "summary": "Platform status and 90-day uptime",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/stops/{id}": {
      "get": {
        "operationId": "getStop",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stop"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A stop's progress: pending, failing (retried), completed, superseded or failed",
        "tags": [
          "Sandboxes"
        ]
      }
    },
    "/v1/subscriptions": {
      "get": {
        "operationId": "listSubscriptions",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Subscription"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Subscription sign-ins (Claude, ChatGPT): connected or not",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/subscriptions/{provider}": {
      "delete": {
        "operationId": "signOutSubscription",
        "parameters": [
          {
            "in": "path",
            "name": "provider",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Sign out of a subscription (every sandbox loses it at its next start)",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/subscriptions/{provider}/login": {
      "delete": {
        "operationId": "cancelSubscriptionLogin",
        "parameters": [
          {
            "in": "path",
            "name": "provider",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Cancel the sign-in in progress",
        "tags": [
          "Agents"
        ]
      },
      "get": {
        "operationId": "getSubscriptionLogin",
        "parameters": [
          {
            "in": "path",
            "name": "provider",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionLogin"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The sign-in in progress (stores the credential once it's done)",
        "tags": [
          "Agents"
        ]
      },
      "post": {
        "operationId": "startSubscriptionLogin",
        "parameters": [
          {
            "in": "path",
            "name": "provider",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartSubscriptionLogin"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionLogin"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Start a subscription sign-in in one of your running sandboxes",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/subscriptions/{provider}/login/code": {
      "post": {
        "operationId": "sendSubscriptionCode",
        "parameters": [
          {
            "in": "path",
            "name": "provider",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriptionCode"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionLogin"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Claude: paste the code the sign-in page showed",
        "tags": [
          "Agents"
        ]
      }
    },
    "/v1/telemetry": {
      "delete": {
        "operationId": "removeTelemetry",
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Stop the OpenTelemetry export",
        "tags": [
          "Integrations"
        ]
      },
      "get": {
        "operationId": "getTelemetry",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Telemetry"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "The OpenTelemetry endpoint (null when none)",
        "tags": [
          "Integrations"
        ]
      },
      "put": {
        "operationId": "setTelemetry",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetTelemetry"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TelemetrySaved"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Set the OpenTelemetry endpoint; sends a test export",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/usage": {
      "get": {
        "operationId": "getUsage",
        "parameters": [
          {
            "description": "YYYY-MM: that calendar month at list prices; default the current billing period",
            "in": "query",
            "name": "month",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Usage this billing period: per-second running time, snapshots, what the plan covers",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/waitlist": {
      "post": {
        "operationId": "joinWaitlist",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Waitlist"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "security": [],
        "summary": "Join the waitlist",
        "tags": [
          "Account"
        ]
      }
    },
    "/v1/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Webhook"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Webhooks",
        "tags": [
          "Integrations"
        ]
      },
      "post": {
        "operationId": "addWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewWebhook"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSecret"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Add a webhook (the signing secret is returned once)",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/webhooks/{id}": {
      "delete": {
        "operationId": "removeWebhook",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Remove a webhook",
        "tags": [
          "Integrations"
        ]
      },
      "get": {
        "operationId": "getWebhook",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "One webhook",
        "tags": [
          "Integrations"
        ]
      },
      "patch": {
        "operationId": "updateWebhook",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhook"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Change a webhook's URL, events, name, or pause it (the secret stays)",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1-200, default 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/WebhookDelivery"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Delivery attempts of the last 30 days, newest first",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/webhooks/{id}/rotate": {
      "post": {
        "operationId": "rotateWebhook",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSecret"
                }
              }
            },
            "description": "OK"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "A new signing secret",
        "tags": [
          "Integrations"
        ]
      }
    },
    "/v1/webhooks/{id}/test": {
      "post": {
        "operationId": "testWebhook",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Done"
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Error: {\"error\": {\"code\", \"message\", \"request_id\"}}"
          }
        },
        "summary": "Send a test event now",
        "tags": [
          "Integrations"
        ]
      }
    }
  },
  "security": [
    {
      "bearer": []
    }
  ],
  "servers": [
    {
      "url": "https://api.froogcorp.com"
    }
  ]
}
