{
  "openapi": "3.1.0",
  "info": {
    "title": "Strovio API",
    "version": "1.0.0",
    "description": "File storage for developers and AI agents. Guides: https://strovio.xyz/docs. Agent index: https://strovio.xyz/llms.txt.",
    "contact": {
      "email": "support@strovio.xyz",
      "url": "https://strovio.xyz/docs"
    }
  },
  "externalDocs": {
    "description": "Strovio docs",
    "url": "https://strovio.xyz/docs/api"
  },
  "servers": [
    {
      "url": "https://strovio.xyz/api/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "apiKeyHeader": []
    }
  ],
  "paths": {
    "/files": {
      "get": {
        "operationId": "listFiles",
        "summary": "List files, newest first",
        "parameters": [
          {
            "name": "prefix",
            "in": "query",
            "description": "Only files whose key contains this text.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Values above 1000 are treated as 1000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Files",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "objects",
                    "count"
                  ],
                  "properties": {
                    "objects": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/File"
                      }
                    },
                    "count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_request: limit is not a whole number from 1 to 1000.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: missing, malformed or deleted API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/files/{path}": {
      "parameters": [
        {
          "name": "path",
          "in": "path",
          "required": true,
          "description": "The path you uploaded to, such as reports/q1.pdf, or the full key from a response, such as uploads/<account>/private/reports/q1.pdf. Encode each segment.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "uploadFile",
        "summary": "Upload or replace a file (up to 512 MB)",
        "parameters": [
          {
            "name": "X-Access",
            "in": "header",
            "schema": {
              "$ref": "#/components/schemas/Access"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The raw file bytes. Content-Type is stored with the file.",
          "content": {
            "*/*": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Uploaded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: missing, malformed or deleted API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "file_too_large or storage_quota_exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getFile",
        "summary": "Get a file's details and a download URL",
        "description": "Private files return a signed URL valid for 3600 seconds; public files return their permanent URL.",
        "responses": {
          "200": {
            "description": "File with a download url and expiresIn",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: missing, malformed or deleted API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "file_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "ambiguous_key: the path is both public and private; send the full key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "head": {
        "operationId": "fileExists",
        "summary": "Check whether a file exists",
        "responses": {
          "200": {
            "description": "Exists. Headers: Content-Length, Content-Type, X-Access, Last-Modified."
          },
          "401": {
            "description": "Invalid or missing API key."
          },
          "404": {
            "description": "No such file."
          },
          "409": {
            "description": "The path is both public and private; send the full key."
          }
        }
      },
      "delete": {
        "operationId": "deleteFile",
        "summary": "Permanently delete a file and its share links",
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "key"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "key": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: missing, malformed or deleted API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "file_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "ambiguous_key: the path is both public and private; send the full key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/files/multipart/start": {
      "post": {
        "operationId": "startMultipartUpload",
        "summary": "Start a multipart upload and get signed part URLs",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key",
                  "size"
                ],
                "properties": {
                  "key": {
                    "type": "string",
                    "description": "Path to store the file under, for example videos/demo.mp4."
                  },
                  "size": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 536870912,
                    "description": "Total size in bytes."
                  },
                  "contentType": {
                    "type": "string",
                    "default": "application/octet-stream"
                  },
                  "access": {
                    "$ref": "#/components/schemas/Access"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload started. PUT each part's bytes to its url and keep the ETag header.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "uploadId",
                    "s3Key",
                    "bucket",
                    "parts"
                  ],
                  "properties": {
                    "uploadId": {
                      "type": "string"
                    },
                    "s3Key": {
                      "type": "string"
                    },
                    "bucket": {
                      "type": "string"
                    },
                    "parts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "partNumber",
                          "url",
                          "contentLength"
                        ],
                        "properties": {
                          "partNumber": {
                            "type": "integer"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri"
                          },
                          "contentLength": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: missing, malformed or deleted API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "file_too_large or storage_quota_exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/files/multipart/complete": {
      "post": {
        "operationId": "completeMultipartUpload",
        "summary": "Finish a multipart upload",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "s3Key",
                  "uploadId",
                  "parts",
                  "key"
                ],
                "properties": {
                  "s3Key": {
                    "type": "string"
                  },
                  "uploadId": {
                    "type": "string"
                  },
                  "key": {
                    "type": "string"
                  },
                  "contentType": {
                    "type": "string"
                  },
                  "access": {
                    "$ref": "#/components/schemas/Access"
                  },
                  "parts": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "PartNumber",
                        "ETag"
                      ],
                      "properties": {
                        "PartNumber": {
                          "type": "integer"
                        },
                        "ETag": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Uploaded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            }
          },
          "400": {
            "description": "invalid_request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: missing, malformed or deleted API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden: the s3Key belongs to another account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/files/presign-put": {
      "post": {
        "operationId": "presignUpload",
        "summary": "Get a signed URL to PUT a file directly to storage",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key",
                  "size"
                ],
                "properties": {
                  "key": {
                    "type": "string",
                    "description": "Path to store the file under, for example videos/demo.mp4."
                  },
                  "size": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 536870912,
                    "description": "Total size in bytes."
                  },
                  "contentType": {
                    "type": "string",
                    "default": "application/octet-stream"
                  },
                  "access": {
                    "$ref": "#/components/schemas/Access"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PUT the bytes to putUrl within one hour with the same Content-Type, then call /files/complete.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "putUrl",
                    "s3Key",
                    "bucket"
                  ],
                  "properties": {
                    "putUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "s3Key": {
                      "type": "string"
                    },
                    "bucket": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: missing, malformed or deleted API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "file_too_large or storage_limit_reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/files/complete": {
      "post": {
        "operationId": "completeUpload",
        "summary": "Register a file after a PUT to a presigned URL",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key"
                ],
                "properties": {
                  "key": {
                    "type": "string"
                  },
                  "contentType": {
                    "type": "string"
                  },
                  "access": {
                    "$ref": "#/components/schemas/Access"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Uploaded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            }
          },
          "400": {
            "description": "invalid_request or upload_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "invalid_api_key: missing, malformed or deleted API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An sk_live_ API key from https://strovio.xyz/developer."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    },
    "schemas": {
      "Access": {
        "type": "string",
        "enum": [
          "public",
          "private"
        ],
        "default": "private"
      },
      "File": {
        "type": "object",
        "required": [
          "key",
          "name",
          "size",
          "contentType",
          "access",
          "url"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "uploads/<account>/<access>/<path>"
          },
          "name": {
            "type": "string"
          },
          "size": {
            "type": "integer"
          },
          "contentType": {
            "type": "string"
          },
          "access": {
            "$ref": "#/components/schemas/Access"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public URL, signed URL (get, private files) or null."
          },
          "expiresIn": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Get only: 3600 for private files, null for public."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "code",
          "doc_url"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "What went wrong and what to do next."
          },
          "code": {
            "type": "string",
            "enum": [
              "invalid_api_key",
              "invalid_request",
              "file_not_found",
              "ambiguous_key",
              "file_too_large",
              "storage_quota_exceeded",
              "storage_limit_reached",
              "upload_not_found",
              "forbidden",
              "internal_error"
            ]
          },
          "doc_url": {
            "type": "string",
            "format": "uri",
            "description": "A section of https://strovio.xyz/docs/errors."
          }
        }
      }
    }
  }
}