{
  "openapi": "3.1.0",
  "info": {
    "title": "Orgo API",
    "version": "1.0.0",
    "summary": "Provision and control cloud computers (virtual desktops) for AI agents.",
    "description": "REST API for Orgo: cloud computers for AI agents. Authenticate with a Bearer API key. Full reference and SDK guides: https://docs.orgo.ai.",
    "termsOfService": "https://www.orgo.ai/terms",
    "contact": {
      "name": "Orgo",
      "url": "https://www.orgo.ai"
    }
  },
  "servers": [
    {
      "url": "https://www.orgo.ai",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Orgo developer docs",
    "url": "https://docs.orgo.ai"
  },
  "security": [
    {
      "bearerApiKey": []
    }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Liveness probe",
        "security": [],
        "tags": [
          "system"
        ],
        "responses": {
          "200": {
            "description": "Service is healthy."
          }
        }
      }
    },
    "/api/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Current authenticated account",
        "tags": [
          "account"
        ],
        "responses": {
          "200": {
            "description": "Account profile and tier."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      }
    },
    "/api/account/capacity": {
      "get": {
        "operationId": "getAccountCapacity",
        "summary": "What the account may run, runs and has added, and how many of each size it may still add",
        "tags": [
          "account"
        ],
        "responses": {
          "200": {
            "description": "computers and ram_gb ({ limit, in_use }), added, self_serve_cap, can_add per size, sizes with monthly prices."
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "A workspace-scoped key: capacity needs an account-wide key."
          }
        }
      },
      "post": {
        "operationId": "addAccountCapacity",
        "summary": "Add computers on the card on file, or price them first (dry_run)",
        "description": "Body: { \"size\": \"small\" | \"medium\" | \"large\" | \"xl\" | \"2xl\", \"count\": 1-500, \"os\"?: \"linux\" | \"windows\", \"term\"?: \"monthly\" | \"yearly\", \"dry_run\"?: boolean }. Send an Idempotency-Key header (a UUID) so a retry answers again instead of buying twice. Bounded by the account’s self-serve cap; past it the answer is 403 capacity_cap and the cap can be raised for the account.",
        "tags": [
          "account"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Added (or, for dry_run, priced), with the account’s capacity after it."
          },
          "400": {
            "description": "Invalid request."
          },
          "402": {
            "description": "No paid plan (no_subscription), or the card was declined (card_declined)."
          },
          "403": {
            "description": "Past the self-serve cap (capacity_cap), or a workspace-scoped key."
          },
          "409": {
            "description": "A request with this Idempotency-Key is running, or did not finish."
          },
          "422": {
            "description": "This Idempotency-Key was used for a different request."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      },
      "patch": {
        "operationId": "reduceAccountCapacity",
        "summary": "Keep this many added computers from the next renewal",
        "description": "Body: { \"added_computers\": n }. The current period is paid for, so the reduction takes effect at renewal.",
        "tags": [
          "account"
        ],
        "responses": {
          "200": {
            "description": "The scheduled reduction and the account’s capacity."
          },
          "409": {
            "description": "Running computers use that capacity (in_use)."
          }
        }
      }
    },
    "/api/keys": {
      "get": {
        "operationId": "listApiKeys",
        "summary": "List this account’s API keys (no plaintext)",
        "tags": [
          "auth"
        ],
        "responses": {
          "200": {
            "description": "API key metadata."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      },
      "post": {
        "operationId": "createApiKey",
        "summary": "Create an API key (optionally workspace-scoped)",
        "tags": [
          "auth"
        ],
        "responses": {
          "200": {
            "description": "Newly created key (plaintext shown once)."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      }
    },
    "/api/workspaces": {
      "get": {
        "operationId": "listWorkspaces",
        "summary": "List workspaces (projects) for the account",
        "tags": [
          "workspaces"
        ],
        "responses": {
          "200": {
            "description": "Array of workspaces."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      },
      "post": {
        "operationId": "createWorkspace",
        "summary": "Create a workspace",
        "tags": [
          "workspaces"
        ],
        "responses": {
          "201": {
            "description": "Created workspace."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      }
    },
    "/api/computers": {
      "get": {
        "operationId": "listComputers",
        "summary": "List cloud computers (virtual desktops)",
        "tags": [
          "computers"
        ],
        "responses": {
          "200": {
            "description": "Array of computers."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      },
      "post": {
        "operationId": "createComputer",
        "summary": "Provision a new cloud computer (optionally from a template via template_ref)",
        "tags": [
          "computers"
        ],
        "responses": {
          "201": {
            "description": "Created computer."
          },
          "401": {
            "description": "Unauthenticated."
          },
          "402": {
            "description": "Quota or credit limit reached."
          },
          "409": {
            "description": "template_ref given but the template golden is not built."
          }
        }
      }
    },
    "/api/computers/{id}/public-urls": {
      "get": {
        "operationId": "listPublicUrls",
        "summary": "List a computer’s public URLs",
        "description": "A public URL is https://<label>.<base_domain> (orgo.dev) serving a port inside the computer to anyone with the link. The app must listen on 0.0.0.0:<port>, not 127.0.0.1. Answers { enabled: false, public_urls: [] } where the feature is off or the computer cannot have one (only Linux and Windows computers can).",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          }
        ],
        "responses": {
          "200": {
            "description": "Settings and the list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUrlList"
                },
                "example": {
                  "enabled": true,
                  "base_domain": "orgo.dev",
                  "limit": 5,
                  "public_urls": [
                    {
                      "id": "6f1c2a7e-3b9d-4c1a-9e2f-0a1b2c3d4e5f",
                      "url": "https://cool-thing.orgo.dev",
                      "hostname": "cool-thing.orgo.dev",
                      "label": "cool-thing",
                      "port": 3000,
                      "created_at": "2026-10-05T18:00:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "No access to this computer, or a share-link guest."
          },
          "404": {
            "description": "Computer not found."
          }
        }
      },
      "post": {
        "operationId": "createPublicUrl",
        "summary": "Make a public URL for a port on the computer",
        "description": "Body: { \"port\": 1-65535, \"label\"?: string }. The label is lowercased; 3-40 letters, digits and hyphens, starting and ending with a letter or digit, not all digits, no hyphens in the third and fourth places (ab--), not a reserved name, not shaped like a computer id (8 hex characters or orgo-...). Without one, a name like brave-otter-3f2a is picked. Ports 22, 3389, 5900, 6080, 8080 and 9000 belong to the computer and are refused. Errors are { error, code }. The app must listen on 0.0.0.0:<port>. Cookies the app sets are host-only (a Domain attribute other than the URL’s own hostname is removed).",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePublicUrl"
              },
              "example": {
                "port": 3000,
                "label": "cool-thing"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUrl"
                },
                "example": {
                  "id": "6f1c2a7e-3b9d-4c1a-9e2f-0a1b2c3d4e5f",
                  "url": "https://cool-thing.orgo.dev",
                  "hostname": "cool-thing.orgo.dev",
                  "label": "cool-thing",
                  "port": 3000,
                  "created_at": "2026-10-05T18:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad port (INVALID_PORT), bad label (INVALID_LABEL), or a computer that cannot have one (PUBLIC_URLS_UNSUPPORTED).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Port 8080 is used by the computer itself and cannot be shared. Run your app on another port.",
                  "code": "INVALID_PORT"
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "No access to this computer, or a share-link guest."
          },
          "404": {
            "description": "Public URLs are not enabled here, or the computer was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "public URLs are not enabled"
                }
              }
            }
          },
          "409": {
            "description": "The name is taken (LABEL_TAKEN), or the computer has as many public URLs as it may (PUBLIC_URL_LIMIT).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "This computer already has 5 public URLs, the most it can have. Remove one to add another.",
                  "code": "PUBLIC_URL_LIMIT"
                }
              }
            }
          },
          "429": {
            "description": "Too many public URLs made today by this user (RATE_LIMITED). Retry-After says when to try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "No free generated name was found. Try again."
          }
        }
      }
    },
    "/api/computers/{id}/public-urls/{urlId}": {
      "patch": {
        "operationId": "updatePublicUrl",
        "summary": "Point a public URL at another port",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          },
          {
            "$ref": "#/components/parameters/PublicUrlId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePublicUrl"
              },
              "example": {
                "port": 8000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUrl"
                }
              }
            }
          },
          "400": {
            "description": "Bad port.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "404": {
            "description": "Not found on this computer, or public URLs are not enabled."
          }
        }
      },
      "delete": {
        "operationId": "deletePublicUrl",
        "summary": "Remove a public URL (the app keeps running)",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          },
          {
            "$ref": "#/components/parameters/PublicUrlId"
          }
        ],
        "responses": {
          "204": {
            "description": "Removed."
          },
          "401": {
            "description": "Unauthenticated."
          },
          "404": {
            "description": "Not found on this computer, or public URLs are not enabled."
          }
        }
      }
    },
    "/api/computers/{id}/domains": {
      "get": {
        "operationId": "listCustomDomains",
        "summary": "List a computer’s custom domains, each with the DNS records to set",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          }
        ],
        "responses": {
          "200": {
            "description": "The domains.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domains": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomDomain"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "No access to this computer, or a share-link guest."
          }
        }
      },
      "post": {
        "operationId": "addCustomDomain",
        "summary": "Serve a port on the computer from a domain you own",
        "description": "Body: { \"domain\": \"app.example.com\", \"target_port\"?: 1-65535 } (default 8642; the computer’s own ports are refused). Set every record in dns_records at your DNS provider (a TXT record proving ownership, and a CNAME to the edge, or an A record for an apex domain), then POST /verify. A name under the public URL domain (orgo.dev) is refused. A name held by another account that was never verified within 7 days is taken over.",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string"
                  },
                  "target_port": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 65535
                  }
                }
              },
              "example": {
                "domain": "app.example.com",
                "target_port": 3000
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Added, waiting for DNS.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomDomain"
                },
                "example": {
                  "id": "0b8e6a1c-5d4f-4e3a-8b2c-1d0e9f8a7b6c",
                  "domain": "app.example.com",
                  "status": "pending",
                  "target_port": 3000,
                  "dns": {
                    "type": "TXT",
                    "name": "_orgo-verify.app.example.com",
                    "value": "9f2c4e6a8b0d1f3e5a7c9e1b3d5f7a9c"
                  },
                  "dns_records": [
                    {
                      "type": "TXT",
                      "name": "_orgo-verify.app.example.com",
                      "value": "9f2c4e6a8b0d1f3e5a7c9e1b3d5f7a9c"
                    },
                    {
                      "type": "CNAME",
                      "name": "app.example.com",
                      "value": "edge.orgo.dev"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid domain or port (INVALID_DOMAIN, INVALID_PORT).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "Plan limit, no access, or a share-link guest."
          },
          "409": {
            "description": "That domain is already in use."
          }
        }
      }
    },
    "/api/computers/{id}/domains/{domainId}": {
      "get": {
        "operationId": "getCustomDomain",
        "summary": "Get one custom domain with its DNS records",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          },
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomDomain"
                }
              }
            }
          },
          "404": {
            "description": "Not found on this computer."
          }
        }
      },
      "delete": {
        "operationId": "deleteCustomDomain",
        "summary": "Remove a custom domain",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          },
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ deleted: true }"
          },
          "404": {
            "description": "Not found on this computer."
          },
          "409": {
            "description": "Orgo turned the domain off ({ status: \"disabled\" }); contact support to remove it."
          }
        }
      }
    },
    "/api/computers/{id}/domains/{domainId}/verify": {
      "post": {
        "operationId": "verifyCustomDomain",
        "summary": "Check the TXT record and where the domain points, and turn it on",
        "tags": [
          "public-urls"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ComputerId"
          },
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ status: \"active\" }"
          },
          "403": {
            "description": "Custom-domain limit reached."
          },
          "404": {
            "description": "Not found on this computer."
          },
          "409": {
            "description": "The TXT record is not visible yet ({ status: \"verifying\" }); the TXT record is there but the domain does not point at the edge yet ({ status: \"verifying\", code: \"DNS_NOT_POINTED\", dns_records }); or Orgo turned the domain off ({ status: \"disabled\" }).",
            "content": {
              "application/json": {
                "example": {
                  "status": "verifying",
                  "code": "DNS_NOT_POINTED",
                  "error": "Point app.example.com at edge.orgo.dev (CNAME record), then verify again.",
                  "dns_records": [
                    {
                      "type": "TXT",
                      "name": "_orgo-verify.app.example.com",
                      "value": "9f2c4e6a8b0d1f3e5a7c9e1b3d5f7a9c"
                    },
                    {
                      "type": "CNAME",
                      "name": "app.example.com",
                      "value": "edge.orgo.dev"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/templates": {
      "get": {
        "operationId": "listTemplates",
        "summary": "List templates you have published",
        "tags": [
          "templates"
        ],
        "responses": {
          "200": {
            "description": "Your templates."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      },
      "post": {
        "operationId": "publishTemplate",
        "summary": "Publish a template version (raw YAML/JSON body; requires the Scale plan)",
        "tags": [
          "templates"
        ],
        "responses": {
          "201": {
            "description": "Published version."
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "Requires the Scale plan."
          },
          "422": {
            "description": "Template validation failed."
          }
        }
      }
    },
    "/api/templates/apps": {
      "get": {
        "operationId": "listTemplateApps",
        "summary": "List the apps a template can install, each with the YAML fragment picking it contributes",
        "tags": [
          "templates"
        ],
        "responses": {
          "200": {
            "description": "The app catalog."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      }
    },
    "/api/templates/global": {
      "get": {
        "operationId": "listGlobalTemplates",
        "summary": "List curated templates you can deploy from (pass the ref as template_ref to POST /api/computers)",
        "tags": [
          "templates"
        ],
        "responses": {
          "200": {
            "description": "Curated templates."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      }
    },
    "/api/templates/validate": {
      "post": {
        "operationId": "validateTemplate",
        "summary": "Validate a template document with no side effects",
        "tags": [
          "templates"
        ],
        "responses": {
          "200": {
            "description": "Valid."
          },
          "401": {
            "description": "Unauthenticated."
          },
          "422": {
            "description": "Validation failed."
          }
        }
      }
    },
    "/api/templates/{namespace}/{name}/{version}": {
      "get": {
        "operationId": "getTemplate",
        "summary": "Get a template version",
        "tags": [
          "templates"
        ],
        "parameters": [
          {
            "name": "namespace",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The template version."
          },
          "401": {
            "description": "Unauthenticated."
          },
          "404": {
            "description": "Not found."
          }
        }
      },
      "delete": {
        "operationId": "deleteTemplate",
        "summary": "Delete a template version everywhere",
        "description": "Deletes the version everywhere: cancels its queued builds and removes the durable record and the host entry immediately, so the version is gone from listings and cannot be launched or built as soon as this returns. The golden archive is removed from every registry after a grace period of about 30 minutes (computers launched from it may still stream it that long) — running computers are unaffected. Idempotent — a repeat returns 200 with deleted:true. The same version can be re-published with new content immediately.",
        "tags": [
          "templates"
        ],
        "parameters": [
          {
            "name": "namespace",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted (or already gone): { deleted: true, cancelledJobs: <queued builds cancelled> }."
          },
          "401": {
            "description": "Unauthenticated."
          },
          "502": {
            "description": "golden_delete_incomplete — the version still exists; retry."
          },
          "503": {
            "description": "delete_authority_unavailable — the durable record could not be reached; the version still exists; retry."
          }
        }
      }
    },
    "/api/templates/{namespace}/{name}/{version}/build": {
      "post": {
        "operationId": "buildTemplate",
        "summary": "Build a template golden image so deploys are instant (requires the Scale plan)",
        "tags": [
          "templates"
        ],
        "parameters": [
          {
            "name": "namespace",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Build started."
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "Requires the Scale plan."
          }
        }
      },
      "get": {
        "operationId": "getTemplateBuildStatus",
        "summary": "Poll golden build status (not_built | building | ready | failed)",
        "tags": [
          "templates"
        ],
        "parameters": [
          {
            "name": "namespace",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Build status."
          },
          "401": {
            "description": "Unauthenticated."
          }
        }
      }
    },
    "/api/v1/invoices": {
      "post": {
        "operationId": "createInvoice",
        "summary": "Invoice anyone for anything, paid into your connected bank account",
        "description": "Creates and finalizes a one-off invoice and answers with `url`, the Stripe page where your customer pays it (card). Nothing is sent: share `url`, or POST /api/v1/invoices/{id}/send to email it from your business name. Amounts are integer cents. Give `amount`, or `line_items` (then `amount` may be left out, or must equal their total). `customer` needs an email or a phone. `due_date` is a date (2026-11-01, due at the end of that day UTC) or unix seconds, within 365 days; without one the invoice is due 30 days after it is made. Every create needs an Idempotency-Key header (a UUID, new for each invoice): a retry with the same key within 24 hours answers with the same invoice instead of making a second one.\n\nMoney: a destination charge to your Stripe Connect account, made on its behalf, so the invoice, the payment page and the card statement carry your business name. Orgo keeps only what Stripe charges it for the invoice, the card fee (2.9% + 30¢) and the Invoicing fee (0.5%), as `orgo_fee`; `payout` is paid out to you. Needs Invoicing (every paid plan) and payouts set up in Settings → Invoicing. Use an account-wide API key.",
        "tags": [
          "invoices"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "A new key for each invoice, such as a UUID. Send the same key again only to retry that invoice.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInvoice"
              },
              "example": {
                "amount": 120000,
                "currency": "usd",
                "description": "March security audit",
                "customer": {
                  "email": "ap@acme.com",
                  "name": "Acme Inc."
                },
                "due_date": "2026-11-01",
                "metadata": {
                  "project": "audit-2026-03"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created and open. `url` is where the customer pays.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "400": {
            "description": "Bad input (invalid_request, with `param`), no Idempotency-Key header (idempotency_key_required), or a malformed one (invalid_idempotency_key).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "amount must be at least 50 cents ($0.50).",
                  "code": "invalid_request",
                  "param": "amount"
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "Invoicing is off for this account (UPGRADE_REQUIRED on Free, MANAGED_ACCOUNTS_DISABLED), or a workspace-scoped key."
          },
          "404": {
            "description": "workspace_id is not a workspace you can write to (workspace_not_found)."
          },
          "409": {
            "description": "Payouts are not set up yet (payouts_not_ready, with `connect_url`), or a request with this Idempotency-Key is still running (idempotency_in_progress).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Connect a bank account first, so you can be paid. Set up payouts in Settings → Invoicing.",
                  "code": "payouts_not_ready",
                  "connect_url": "https://www.orgo.ai/settings/invoicing"
                }
              }
            }
          },
          "422": {
            "description": "This Idempotency-Key was used for a different invoice (idempotency_key_reused), or the invoice it made was discarded (idempotency_key_spent). Use a new key."
          },
          "502": {
            "description": "Stripe did not answer (stripe_unavailable). Retry with the same Idempotency-Key."
          },
          "503": {
            "description": "Invoicing is not available yet (invoicing_unavailable), or the invoice could not be saved (invoice_not_saved; the error says whether to retry with a new or the same Idempotency-Key)."
          }
        }
      },
      "get": {
        "operationId": "listInvoices",
        "summary": "Your invoices, newest first",
        "description": "Read from Orgo’s record of your invoices, so a new invoice is here as soon as it is made. Statuses and amounts follow Stripe: they are updated on each of Stripe’s invoice events and whenever you read, send or void one, so a payment can take a few seconds to show here; GET /api/v1/invoices/{id} reads Stripe at once. Pass `next_cursor` back as `cursor` for the next page, with the same filters.",
        "tags": [
          "invoices"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/InvoiceStatus"
            }
          },
          {
            "name": "workspace_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of invoices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceList"
                }
              }
            }
          },
          "400": {
            "description": "Bad status, workspace_id or cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "403": {
            "description": "Invoicing is off for this account, or a workspace-scoped key."
          },
          "503": {
            "description": "Invoicing is not available yet (invoicing_unavailable)."
          }
        }
      }
    },
    "/api/v1/invoices/{id}": {
      "get": {
        "operationId": "getInvoice",
        "summary": "One invoice, with its current status (open, paid, void, uncollectible)",
        "tags": [
          "invoices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/InvoiceId"
          }
        ],
        "responses": {
          "200": {
            "description": "The invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "404": {
            "description": "Not one of your invoices (invoice_not_found)."
          }
        }
      }
    },
    "/api/v1/invoices/{id}/send": {
      "post": {
        "operationId": "sendInvoice",
        "summary": "Email the invoice to the customer, from your business name",
        "description": "Sends again on a later call, so it is also the reminder, but at most once a minute: a second send within a minute, at the same time or as a retry, emails nothing and answers 409 invoice_recently_sent. Replies go to your account email.",
        "tags": [
          "invoices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/InvoiceId"
          }
        ],
        "responses": {
          "200": {
            "description": "Sent. `last_sent_at` says when.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "404": {
            "description": "Not one of your invoices (invoice_not_found)."
          },
          "409": {
            "description": "Already paid (invoice_paid), void (invoice_void), the customer has no email (no_customer_email, with `url` to share yourself), or it was emailed less than a minute ago (invoice_recently_sent, with `last_sent_at`)."
          },
          "502": {
            "description": "The email did not send (email_failed, with `url`). The invoice is still open, and you can send again at once."
          },
          "503": {
            "description": "Invoicing is not available yet (invoicing_unavailable)."
          }
        }
      }
    },
    "/api/v1/invoices/{id}/void": {
      "post": {
        "operationId": "voidInvoice",
        "summary": "Cancel an unpaid invoice; its page stops taking payment",
        "tags": [
          "invoices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/InvoiceId"
          }
        ],
        "responses": {
          "200": {
            "description": "Void (voiding a void invoice answers the same).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "401": {
            "description": "Unauthenticated."
          },
          "404": {
            "description": "Not one of your invoices (invoice_not_found)."
          },
          "409": {
            "description": "Paid invoices cannot be voided (invoice_paid)."
          }
        }
      }
    },
    "/api/v1/chat/completions": {
      "post": {
        "operationId": "runComputerAgent",
        "summary": "Run an agent on a computer: OpenAI-shaped chat completions that drive the desktop",
        "description": "Sends the conversation to a model that operates the computer named by `computer_id` (clicks, types, runs commands) until it answers. The request and response follow OpenAI chat completions, plus `computer_id` and an `orgo` block, so the OpenAI SDKs work with base URL `https://www.orgo.ai/api/v1`. `messages[].content` is a string or OpenAI content parts (`text`, and `image_url` as an https or base64 data URL in user messages). Roles other than user and assistant are dropped, and the first remaining message must be from the user. With `stream: true` the answer arrives as `chat.completion.chunk` Server-Sent Events ending in `data: [DONE]`; only text streams, and the thread id is in the `X-Thread-Id` header. A stream that ends without a chunk carrying a `finish_reason` failed. Closing the connection stops the run at its next step; steps already taken are billed.\n\nA run takes up to 250 model steps. `max_steps` raises that, up to 500; it never lowers it. A run that reaches its limit finishes with `finish_reason: \"length\"`. Billed from AI credits by the workspace owner, unless you send your own Anthropic key in `x-anthropic-key` with an Anthropic-served model.",
        "tags": [
          "agent"
        ],
        "parameters": [
          {
            "name": "x-anthropic-key",
            "in": "header",
            "required": false,
            "description": "Your own Anthropic key. For an Anthropic-served model, the run uses it and is not billed to credits; other models ignore it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "computer_id",
                  "messages"
                ],
                "properties": {
                  "computer_id": {
                    "type": "string",
                    "description": "The computer to drive (its id or instance id). It must be running."
                  },
                  "messages": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "required": [
                        "role",
                        "content"
                      ],
                      "properties": {
                        "role": {
                          "type": "string",
                          "description": "user or assistant. Other roles are accepted and dropped."
                        },
                        "content": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "array",
                              "items": {
                                "oneOf": [
                                  {
                                    "type": "object",
                                    "required": [
                                      "type",
                                      "text"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "text"
                                      },
                                      "text": {
                                        "type": "string"
                                      }
                                    }
                                  },
                                  {
                                    "type": "object",
                                    "required": [
                                      "type",
                                      "image_url"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "image_url"
                                      },
                                      "image_url": {
                                        "type": "object",
                                        "required": [
                                          "url"
                                        ],
                                        "properties": {
                                          "url": {
                                            "type": "string",
                                            "description": "https URL or base64 data URL (png, jpeg, gif, webp)."
                                          }
                                        }
                                      }
                                    }
                                  }
                                ]
                              }
                            }
                          ]
                        }
                      }
                    }
                  },
                  "model": {
                    "type": "string",
                    "description": "Leave it out to get Orgo’s recommended engine for the computer: `orgo-agent` (Computer Use) on Linux, Windows, macOS and iPhone computers, Claude Sonnet 5 on others or with your own Anthropic key. Name one to pin it.",
                    "enum": [
                      "orgo-agent",
                      "orgo-agent-opus-5.5",
                      "claude-sonnet-5",
                      "claude-opus-5.5",
                      "claude-opus-5",
                      "claude-opus-4.8",
                      "claude-sonnet-4.6",
                      "claude-opus-4.6"
                    ]
                  },
                  "stream": {
                    "type": "boolean",
                    "default": false
                  },
                  "thread_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Continue a stored thread on this computer. Unknown ids start a new thread."
                  },
                  "max_steps": {
                    "type": "integer",
                    "minimum": 250,
                    "maximum": 500,
                    "default": 250,
                    "description": "Raise the step limit. Lower values are treated as 250."
                  }
                }
              },
              "example": {
                "model": "claude-sonnet-5",
                "computer_id": "a3bb189e-8bf9-3888-9912-ace4e6543002",
                "messages": [
                  {
                    "role": "user",
                    "content": "Open Firefox and find the weather in Paris."
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The final answer. With `stream: true`, an event stream instead.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "object": {
                      "type": "string",
                      "const": "chat.completion"
                    },
                    "created": {
                      "type": "integer"
                    },
                    "model": {
                      "type": "string"
                    },
                    "choices": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "usage": {
                      "type": "object",
                      "properties": {
                        "prompt_tokens": {
                          "type": "integer"
                        },
                        "completion_tokens": {
                          "type": "integer"
                        },
                        "total_tokens": {
                          "type": "integer"
                        }
                      }
                    },
                    "orgo": {
                      "type": "object",
                      "properties": {
                        "thread_id": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "steps": {
                          "type": "integer"
                        },
                        "cost_cents": {
                          "type": "integer"
                        },
                        "credit_balance_cents": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad input: missing_computer_id, invalid_model, invalid_messages (with `param`), empty_messages, invalid_message_order, invalid_json, model_unsupported_os, or context_overflow."
          },
          "401": {
            "description": "Invalid API key (invalid_api_key)."
          },
          "402": {
            "description": "Out of AI credits (credits_exhausted), or a managed account at its monthly AI limit (account_ai_limit)."
          },
          "403": {
            "description": "AI is turned off for this account."
          },
          "404": {
            "description": "The computer does not exist or is not yours (computer_not_found)."
          },
          "500": {
            "description": "The run failed (internal_error). Steps it took are billed."
          },
          "503": {
            "description": "The model is not available right now (model_not_configured)."
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "ComputerId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Computer id.",
        "schema": {
          "type": "string"
        }
      },
      "PublicUrlId": {
        "name": "urlId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "InvoiceId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Invoice id (in_...).",
        "schema": {
          "type": "string",
          "pattern": "^in_[A-Za-z0-9]+$"
        }
      }
    },
    "schemas": {
      "InvoiceStatus": {
        "type": "string",
        "enum": [
          "draft",
          "open",
          "paid",
          "void",
          "uncollectible"
        ]
      },
      "InvoiceLineItemInput": {
        "type": "object",
        "required": [
          "description",
          "unit_amount"
        ],
        "properties": {
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "unit_amount": {
            "type": "integer",
            "minimum": 1,
            "description": "Price of one, in cents."
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000,
            "default": 1
          }
        }
      },
      "CreateInvoice": {
        "type": "object",
        "required": [
          "description",
          "customer"
        ],
        "properties": {
          "amount": {
            "type": "integer",
            "minimum": 50,
            "maximum": 10000000,
            "description": "Total in cents. Required without line_items."
          },
          "currency": {
            "type": "string",
            "enum": [
              "usd"
            ],
            "default": "usd"
          },
          "description": {
            "type": "string",
            "maxLength": 1000,
            "description": "What it is for; shown on the invoice and in the email."
          },
          "line_items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/InvoiceLineItemInput"
            }
          },
          "customer": {
            "type": "object",
            "description": "Who pays. An email or a phone is required.",
            "properties": {
              "email": {
                "type": "string",
                "format": "email"
              },
              "phone": {
                "type": "string",
                "example": "+15551234567"
              },
              "name": {
                "type": "string",
                "maxLength": 256
              }
            }
          },
          "due_date": {
            "oneOf": [
              {
                "type": "string",
                "description": "A date or date-time."
              },
              {
                "type": "integer",
                "description": "Unix seconds."
              }
            ]
          },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Your own keys (not `type` or `orgo_*`), returned as sent."
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid",
            "description": "Tag it with one of your workspaces, to filter the list by."
          }
        }
      },
      "Invoice": {
        "type": "object",
        "required": [
          "id",
          "status",
          "amount",
          "currency",
          "url",
          "created"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "in_1QxYz2AbCdEf"
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "amount": {
            "type": "integer",
            "description": "Total, in cents."
          },
          "amount_paid": {
            "type": "integer"
          },
          "amount_remaining": {
            "type": "integer"
          },
          "currency": {
            "type": "string",
            "example": "usd"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stripe’s hosted invoice page, where the customer pays."
          },
          "pdf_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "number": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "customer": {
            "type": "object",
            "properties": {
              "email": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "phone": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "line_items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "description": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "quantity": {
                  "type": "integer"
                },
                "unit_amount": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "amount": {
                  "type": "integer"
                }
              }
            }
          },
          "due_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created": {
            "type": "string",
            "format": "date-time"
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "voided_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "orgo_fee": {
            "type": "integer",
            "description": "Orgo’s fee in cents: Stripe’s card and Invoicing fees."
          },
          "payout": {
            "type": "integer",
            "description": "What reaches your bank when it is paid, in cents."
          },
          "workspace_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "example": {
          "id": "in_1QxYz2AbCdEf",
          "status": "open",
          "amount": 120000,
          "amount_paid": 0,
          "amount_remaining": 120000,
          "currency": "usd",
          "url": "https://invoice.stripe.com/i/acct_123/test_abc",
          "pdf_url": "https://pay.stripe.com/invoice/acct_123/test_abc/pdf",
          "number": "A1B2C3D4-0001",
          "description": "March security audit",
          "customer": {
            "email": "ap@acme.com",
            "phone": null,
            "name": "Acme Inc."
          },
          "line_items": [
            {
              "description": "March security audit",
              "quantity": 1,
              "unit_amount": 120000,
              "amount": 120000
            }
          ],
          "due_date": "2026-11-01T23:59:59.000Z",
          "created": "2026-10-07T18:00:00.000Z",
          "paid_at": null,
          "voided_at": null,
          "last_sent_at": null,
          "orgo_fee": 4110,
          "payout": 115890,
          "workspace_id": null,
          "metadata": {
            "project": "audit-2026-03"
          }
        }
      },
      "InvoiceList": {
        "type": "object",
        "required": [
          "invoices",
          "next_cursor"
        ],
        "properties": {
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Invoice"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        }
      },
      "PublicUrl": {
        "type": "object",
        "required": [
          "id",
          "url",
          "hostname",
          "label",
          "port",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://cool-thing.orgo.dev"
          },
          "hostname": {
            "type": "string",
            "example": "cool-thing.orgo.dev"
          },
          "label": {
            "type": "string",
            "example": "cool-thing"
          },
          "port": {
            "type": "integer",
            "minimum": 1,
            "maximum": 65535
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PublicUrlList": {
        "type": "object",
        "required": [
          "enabled",
          "public_urls"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "False where the feature is off or this computer cannot have public URLs."
          },
          "reason": {
            "type": "string",
            "description": "Why enabled is false for this computer, when that is the reason."
          },
          "base_domain": {
            "type": "string",
            "example": "orgo.dev"
          },
          "limit": {
            "type": "integer",
            "description": "Most public URLs this computer may have; negative means no cap."
          },
          "public_urls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicUrl"
            }
          }
        }
      },
      "CreatePublicUrl": {
        "type": "object",
        "required": [
          "port"
        ],
        "properties": {
          "port": {
            "type": "integer",
            "minimum": 1,
            "maximum": 65535,
            "not": {
              "enum": [
                22,
                3389,
                5900,
                6080,
                8080,
                9000
              ]
            }
          },
          "label": {
            "type": "string",
            "minLength": 3,
            "maxLength": 40,
            "pattern": "^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$"
          }
        }
      },
      "UpdatePublicUrl": {
        "type": "object",
        "required": [
          "port"
        ],
        "properties": {
          "port": {
            "type": "integer",
            "minimum": 1,
            "maximum": 65535,
            "not": {
              "enum": [
                22,
                3389,
                5900,
                6080,
                8080,
                9000
              ]
            }
          }
        }
      },
      "DnsRecord": {
        "type": "object",
        "required": [
          "type",
          "name",
          "value"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "TXT",
              "CNAME",
              "A"
            ]
          },
          "name": {
            "type": "string"
          },
          "value": {
            "type": "string"
          }
        }
      },
      "CustomDomain": {
        "type": "object",
        "required": [
          "id",
          "domain",
          "status",
          "target_port",
          "dns_records"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "domain": {
            "type": "string",
            "example": "app.example.com"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "verifying",
              "active",
              "failed",
              "disabled"
            ]
          },
          "target_port": {
            "type": "integer"
          },
          "verified_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "dns": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DnsRecord"
              },
              {
                "type": "null"
              }
            ],
            "description": "The TXT challenge alone, null once active. Kept for older clients."
          },
          "dns_records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DnsRecord"
            },
            "description": "Every record to set: the TXT challenge, then a CNAME to the edge (an A record for an apex)."
          }
        }
      }
    },
    "securitySchemes": {
      "bearerApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Orgo API key",
        "description": "Create a key in the dashboard or via POST /api/keys, then send `Authorization: Bearer <key>`."
      }
    }
  },
  "tags": [
    {
      "name": "system"
    },
    {
      "name": "account"
    },
    {
      "name": "auth"
    },
    {
      "name": "workspaces"
    },
    {
      "name": "computers"
    },
    {
      "name": "public-urls",
      "description": "Share an app running on a computer: public URLs and custom domains."
    },
    {
      "name": "templates"
    },
    {
      "name": "invoices",
      "description": "Bill your own customers: one-off invoices paid into your connected bank account."
    },
    {
      "name": "agent",
      "description": "Run an AI agent that operates a computer."
    }
  ]
}