{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/juzpost/json-schema/juzpost-presign-request-schema.json",
  "title": "PresignRequest",
  "description": "What you want to upload or download. Supply exactly one of `relativeKey` (preferred) or\n`key`; both resolve to a path under your own storage prefix.\n",
  "x-generated": "2026-11-08",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/juzpost-openapi.json#/components/schemas/PresignRequest",
  "type": "object",
  "required": [
    "contentType"
  ],
  "properties": {
    "relativeKey": {
      "type": "string",
      "minLength": 1,
      "description": "Path for the object relative to your storage prefix, such as\n`media/clip_03.mp4`. Only letters, digits, `.`, `_`, `-` and `/` are allowed, and\n`..` segments are rejected. The server prepends your storage prefix and returns\nthe result as `resolvedKey`.\n"
    },
    "key": {
      "type": "string",
      "minLength": 1,
      "description": "A full storage key, used instead of `relativeKey`, normally only for\n`operation: download` of a key you already hold. It must already start with your own\nstorage prefix or the request is refused with `403`.\n"
    },
    "contentType": {
      "type": "string",
      "minLength": 1,
      "description": "MIME type of the object, such as `video/mp4` or `image/jpeg`. It is bound into the\nsignature, so the PUT must send exactly this same `Content-Type`. It also selects\nthe size cap: 500 MB for `video/*`, 15 MB for `image/*`, 10 MB for anything else.\n"
    },
    "contentLength": {
      "type": "integer",
      "minimum": 1,
      "description": "Exact byte length of the object you are about to upload. Required for uploads and\nignored for downloads. It is bound into the signature, so a PUT of a different size\nis rejected by storage, and it is counted against your storage quota as soon as\nthe URL is issued.\n"
    },
    "operation": {
      "type": "string",
      "description": "`upload` presigns a PUT for new bytes; `download` presigns a GET for an object that\nalready exists. Downloads skip the quota and rate-limit checks.\n",
      "enum": [
        "upload",
        "download"
      ],
      "default": "upload"
    },
    "expiresInSeconds": {
      "type": "integer",
      "minimum": 60,
      "maximum": 86400,
      "default": 300,
      "description": "How long the returned URL stays valid, between 60 seconds and one day. Keep it short:\nwhoever holds the URL can use it until it expires. Allow generous client-side\ntimeouts for large uploads within this window.\n"
    }
  }
}