{
  "service": "Nightcord Storage",
  "version": "2.0.0",
  "description": "Object storage proxy with SEKAI v2 resource facade. Legacy upload paths remain; new clients should prefer /v2/upload and typed resolve URLs.",
  "hosts": {
    "storage": "https://storage.nightcord.de5.net",
    "r2": "https://r2.nightcord.de5.net",
    "note": "Both hosts hit this Worker when bound. Prefer the media host for public SEKAI GETs; uploads may use either host."
  },
  "sekaiv2": {
    "upload": {
      "method": "PUT",
      "path": "/v2/upload",
      "headers": {
        "X-Filename": "percent-encoded original filename (required)",
        "Content-Type": "MIME type",
        "Content-Length": "bytes",
        "X-Sekai-Kind": "image | file | sticker (optional; inferred from MIME)",
        "X-Image-Width": "optional int",
        "X-Image-Height": "optional int"
      },
      "response": {
        "uuid": "resource id (use as SEKAI payload)",
        "key": "same as uuid",
        "type": "MIME",
        "size": "kilobytes (float)",
        "size_bytes": "bytes",
        "name": "original filename",
        "kind": "image | file | sticker",
        "url": "/images/{uuid} or /files/{uuid} or /stickers/{uuid}",
        "w": "optional",
        "h": "optional"
      },
      "example": "curl -X PUT https://storage.nightcord.de5.net/v2/upload -H \"X-Filename: photo.jpg\" -H \"Content-Type: image/jpeg\" --data-binary @photo.jpg",
      "limits": {
        "anonymous_max_bytes": 536870912,
        "authenticated_max_bytes": 1048576000,
        "note": "Uploads up to 512 MiB are anonymous. Larger uploads (up to ~1GB) require a SEKAI Pass access token via 'Authorization: Bearer <token>'; without one they return 401. Over ~1GB returns 413. Note: Cloudflare per-plan request-body limits may cap large uploads below this (Free/Pro 100MB, Business 200MB, Enterprise 500MB default)."
      },
      "auth": {
        "header": "Authorization: Bearer <sekai-pass-access-token>",
        "required_when": "Content-Length > 536870912 (512 MiB)"
      }
    },
    "resolve": {
      "methods": [
        "GET",
        "HEAD"
      ],
      "paths": [
        "/images/{uuid}",
        "/files/{uuid}",
        "/stickers/{uuid}"
      ],
      "notes": [
        "UUID is a standard UUID v4 string.",
        "Objects are stored under AttachFiles/sekai/{uuid}{ext} on OSS.",
        "Public Cache-Control: immutable (long TTL) for successful GETs."
      ]
    },
    "meta": {
      "method": "GET",
      "path": "/v2/meta/{uuid}",
      "description": "JSON metadata written at upload time (best-effort)."
    },
    "message_payload": {
      "image": "<$SEKAI:Image:w=…;h=…;name=…:{uuid}>",
      "file": "<$SEKAI:Files:type=…;size=…;name=…:{uuid}>",
      "custom_stamp": "<$SEKAI:Stamp:custom=true:{uuid}>"
    }
  },
  "legacy": {
    "upload": {
      "method": "PUT",
      "path": "/",
      "headers": [
        "X-Filename",
        "Content-Type",
        "Content-Length"
      ],
      "optional": [
        "X-Safe-Path",
        "X-Chunk-Index / X-Chunk-Total / X-File-ID (chunked)"
      ],
      "response": {
        "key": "{uid}/{fileUuid}.ext",
        "url": "/{key}",
        "size": "bytes"
      }
    },
    "resolve": {
      "methods": [
        "GET",
        "HEAD",
        "DELETE"
      ],
      "path": "/{key}",
      "chunked": "/chunked/{inner}"
    }
  },
  "caching": {
    "eligible": "Public media (images/files/stickers, legacy keys). Exclude / and /v2/* from cache eligibility.",
    "see": "Cloudflare Cache Rules on storage.* and r2.*"
  },
  "policy": {
    "summary": "Anonymous file service. Arbitrary file types are allowed (including executables). Illegal content is prohibited and removed on report. Stored objects are served as downloads (Content-Disposition: attachment) with X-Content-Type-Options: nosniff.",
    "report": "Report abuse or illegal content to abuse@nightcord.de5.net. Include the public URL and the reason. Do NOT attach or re-upload the offending content.",
    "report_email": "abuse@nightcord.de5.net",
    "terms": "https://nightcord.de5.net (see Nightcord user terms)"
  },
  "links": {
    "self_html": "https://storage.nightcord.de5.net/",
    "self_json": "https://storage.nightcord.de5.net/?format=json",
    "self_markdown": "https://storage.nightcord.de5.net/?format=md",
    "sekaiv2_docs": "https://storage.nightcord.de5.net/v2",
    "accept_markdown": "Send Accept: text/markdown for this document as Markdown (agents)."
  }
}