{
  "openapi": "3.1.0",
  "info": {
    "title": "CloudCDN API",
    "description": "# CloudCDN API\n\nEnterprise-grade asset delivery on Cloudflare's global edge network. 300+ PoPs, sub-100ms TTFB, 1,400+ assets across 54 tenant zones.\n\n## Quickstart\n\n```bash\n# List all assets\ncurl -H 'AccessKey: YOUR_KEY' https://cloudcdn.pro/api/assets\n\n# Upload a file\ncurl -X PUT -H 'AccessKey: YOUR_KEY' \\\n  -T logo.svg \\\n  https://cloudcdn.pro/api/storage/clients/myproject/v1/logos/logo.svg\n\n# Transform an image\ncurl 'https://cloudcdn.pro/api/transform?url=/myproject/v1/logos/logo.svg&w=400&format=webp'\n```\n\n## Authentication\n\nCloudCDN uses two separate API keys to isolate data-plane and control-plane access:\n\n| Key | Header | Scope |\n|-----|--------|-------|\n| **AccessKey** | `AccessKey` | Storage, Assets — upload, download, browse |\n| **AccountKey** | `AccountKey` | Core, Insights — zones, domains, rules, analytics |\n\nPass the key in the request header:\n\n```bash\ncurl -H 'AccessKey: sk_live_abc123' https://cloudcdn.pro/api/assets\n```\n\nPublic endpoints (Transform, Auto-format, Search, Chat) require no authentication.\n\n## Base URL\n\n| Environment | URL |\n|-------------|-----|\n| Production | `https://cloudcdn.pro` |\n| Local Dev | `http://localhost:8788` |\n\n## Client Libraries\n\nPre-built client libraries for every endpoint. Copy-paste ready.\n\n### JavaScript (ES Module)\n\n```javascript\nimport { listAssets, storageUpload, transformImage } from './clients/javascript.js';\n\n// List all SVG assets\nconst result = await listAssets({ format: 'svg', per_page: 50 });\nconsole.log(result.Data);\n\n// Upload a file\nawait storageUpload('clients/myproject/v1/logos/logo.svg', fileBuffer);\n\n// Transform on the fly\nconst img = await transformImage({ url: '/myproject/v1/logos/logo.svg', w: 400, format: 'webp' });\n```\n\n[Download javascript.js](/api-reference/clients/javascript.js)\n\n### TypeScript\n\n```typescript\nimport { listAssets, type ListAssetsParams } from './clients/typescript';\n\nconst params: ListAssetsParams = { project: 'akande', format: 'svg' };\nconst result = await listAssets(params);\n```\n\n[Download typescript.ts](/api-reference/clients/typescript.ts)\n\n### Python\n\n```python\nfrom clients.python import list_assets, storage_upload\n\nassets = list_assets(project='akande', format='svg')\nfor asset in assets['Data']:\n    print(asset['Path'])\n```\n\n[Download python.py](/api-reference/clients/python.py)\n\n### cURL\n\n```bash\n# List all SVG assets\ncurl -s -H 'AccessKey: sk_live_abc123' \\\n  'https://cloudcdn.pro/api/assets?format=svg&per_page=50'\n\n# Upload a file\ncurl -X PUT -H 'AccessKey: sk_live_abc123' \\\n  -H 'Content-Type: image/svg+xml' \\\n  -T ./logo.svg \\\n  'https://cloudcdn.pro/api/storage/clients/myproject/v1/logos/logo.svg'\n\n# Transform an image (public — no key needed)\ncurl -o thumbnail.webp \\\n  'https://cloudcdn.pro/api/transform?url=/myproject/v1/logos/logo.svg&w=400&format=webp'\n\n# Create a zone\ncurl -X POST -H 'AccountKey: ak_live_xyz789' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"Name\": \"newclient\"}' \\\n  'https://cloudcdn.pro/api/core/zones'\n\n# Purge cache by tag\ncurl -X POST -H 'x-api-key: pk_live_purge' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"tags\": [\"project-akande\"]}' \\\n  'https://cloudcdn.pro/api/purge'\n```\n\n### Shell Helper\n\nSource the shell client for reusable functions:\n\n```bash\nsource clients/curl.sh\nexport CLOUDCDN_ACCESS_KEY='sk_live_abc123'\nlistAssets   # calls GET /api/assets\n```\n\n[Download curl.sh](/api-reference/clients/curl.sh)\n\n## Rate Limits\n\n| Endpoint | Limit |\n|----------|-------|\n| Image Transform | 50,000/month |\n| Cache Purge | 100/day |\n| Chat Concierge | 1,000/month |\n| Storage Upload | No hard limit (GitHub API rate applies) |\n| Asset Catalog | No limit (manifest cached 30s) |\n\n## API Planes\n\n| Plane | Prefix | Purpose |\n|-------|--------|---------|\n| **Storage** | `/api/storage/` | File upload, download, delete, batch |\n| **Core** | `/api/core/` | Zones, domains, rules, statistics |\n| **Assets** | `/api/assets` | Read-only catalog, metadata |\n| **Insights** | `/api/insights/` | Analytics, top assets, geo, errors |\n| **Delivery** | `/api/transform`, `/api/auto`, `/api/signed`, `/api/stream`, `/api/purge` | Edge transforms, format negotiation, signed URLs, HLS, cache |\n| **AI** | `/api/search`, `/api/chat` | Semantic search, RAG concierge |",
    "version": "2026-04-01",
    "contact": {
      "email": "support@cloudcdn.pro"
    },
    "license": {
      "name": "MIT",
      "url": "https://github.com/sebastienrousseau/cloudcdn.pro/blob/main/LICENSE"
    },
    "x-logo": {
      "url": "https://cloudcdn.pro/cloudcdn/v1/logos/cloudcdn.svg",
      "altText": "CloudCDN"
    }
  },
  "servers": [
    {
      "url": "https://cloudcdn.pro",
      "description": "Production edge network"
    },
    {
      "url": "http://localhost:8788",
      "description": "Local development"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Storage",
      "description": "## Storage API\n\nUpload, download, and manage files across your CDN. The Storage API is the write layer — every file mutation flows through here.\n\n### How it works\n\n1. **Upload** a file with `PUT /api/storage/{path}` — committed to the repository via the GitHub Git API\n2. **The CI/CD pipeline** deploys it to 300+ edge locations (~60-90 seconds)\n3. **Download** it instantly via `GET /api/storage/{path}` or the public CDN URL\n\n### Quick start\n\n```bash\n# Upload an SVG logo\ncurl -X PUT -H \"AccessKey: YOUR_KEY\" \\\n  -H \"Content-Type: image/svg+xml\" \\\n  -T ./logo.svg \\\n  https://cloudcdn.pro/api/storage/clients/myproject/v1/logos/logo.svg\n\n# List a directory\ncurl -H \"AccessKey: YOUR_KEY\" \\\n  https://cloudcdn.pro/api/storage/clients/myproject/v1/logos/\n\n# Batch upload (single atomic commit)\ncurl -X POST -H \"AccessKey: YOUR_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"files\": [{ \"path\": \"clients/myproject/v1/logos/logo.svg\", \"content\": \"PHN2Zy4uLg==\", \"encoding\": \"base64\" }] }' \\\n  https://cloudcdn.pro/api/storage/batch\n```\n\n### Authentication\n\nAll Storage endpoints require an **AccessKey** header. This key grants read/write access to files but cannot modify zones or edge configuration.\n\n### Limits\n\n| Limit | Value |\n|-------|-------|\n| Max file size | 25 MB |\n| Max batch size | 50 files |\n| Checksum verification | SHA-256 (optional) |\n| Edge sync | ~60-90 seconds after commit |"
    },
    {
      "name": "Assets",
      "description": "## Assets API\n\nBrowse and search your entire asset catalog. The Assets API is the read-only layer — it queries the auto-generated manifest for instant, filterable access to every file on your CDN.\n\n### How it works\n\nEvery time a file changes, the manifest regenerates automatically. The Assets API reads this manifest (cached 30 seconds at the edge) and provides:\n\n- **Paginated listing** — filter by project, category, format\n- **Full-text search** — across filenames and paths\n- **Per-asset metadata** — size, content type, CDN URL, available formats\n\n### Quick start\n\n```bash\n# List all SVG assets sorted by size\ncurl -H \"AccessKey: YOUR_KEY\" \\\n  'https://cloudcdn.pro/api/assets?format=svg&sort=size&order=desc'\n\n# Search for banking logos\ncurl -H \"AccessKey: YOUR_KEY\" \\\n  'https://cloudcdn.pro/api/assets?q=banking+logo'\n\n# Get metadata for a specific asset\ncurl -H \"AccessKey: YOUR_KEY\" \\\n  'https://cloudcdn.pro/api/assets/metadata?path=akande/v1/logos/akande.svg'\n```\n\n### Pagination\n\nResults paginate with `page` and `per_page` (max 200). The response includes `Pagination.TotalItems`, `Pagination.TotalPages`, and the current page."
    },
    {
      "name": "Core",
      "description": "## Core API\n\nManage your CDN infrastructure — zones, domains, edge rules, and statistics. The Core API is the control plane for platform administrators.\n\n### Zones\n\nA **zone** is a tenant namespace (e.g., `akande`, `bankingonai`). Each zone maps to a directory with a standardized structure:\n\n```\nclients/{zone}/v1/\n  banners/    — Hero images and promotional banners\n  github/     — Social card images for GitHub\n  icons/      — PWA icons (180, 192, 512)\n  logos/       — Brand logos (SVG source)\n  titles/      — Title card images\n```\n\n### Quick start\n\n```bash\n# Create a new zone\ncurl -X POST -H \"AccountKey: YOUR_KEY\" \\\n  -d '{ \"Name\": \"newclient\" }' \\\n  https://cloudcdn.pro/api/core/zones\n\n# Add a custom domain\ncurl -X POST -H \"AccountKey: YOUR_KEY\" \\\n  -d '{ \"Hostname\": \"cdn.newclient.com\" }' \\\n  https://cloudcdn.pro/api/core/zones/newclient/domains\n\n# Update edge caching rules\ncurl -X POST -H \"AccountKey: YOUR_KEY\" \\\n  -d '{ \"File\": \"_headers\", \"Content\": \"/*.webp\\n  Cache-Control: public, max-age=86400\" }' \\\n  https://cloudcdn.pro/api/core/rules\n```\n\n### Authentication\n\nAll Core endpoints require an **AccountKey** header. This is the admin key — it can create/delete zones, manage domains, and modify edge rules. Never share it with CI/CD bots.\n\n### Reserved zone names\n\nThese names cannot be used: `stocks`, `shared`, `website`, `functions`, `api`, `dashboard`, `dist`, `content`, `global`, `clients`."
    },
    {
      "name": "Insights",
      "description": "## Insights API\n\nMonitor your CDN performance in real time. The Insights API provides analytics data collected by the edge middleware on every asset request.\n\n### What is tracked\n\n| Metric | Description |\n|--------|-------------|\n| **Requests** | Total hits per day |\n| **Bandwidth** | Estimated bytes served |\n| **Cache ratio** | Edge hits vs origin misses |\n| **Geography** | Requests by country code |\n| **Top assets** | Most requested files |\n| **Errors** | 4xx/5xx breakdown with paths |\n\n### Quick start\n\n```bash\n# 7-day summary\ncurl -H \"AccountKey: YOUR_KEY\" \\\n  https://cloudcdn.pro/api/insights/summary?days=7\n\n# Top 20 assets this month\ncurl -H \"AccountKey: YOUR_KEY\" \\\n  https://cloudcdn.pro/api/insights/top-assets?days=30&limit=20\n\n# Geographic distribution\ncurl -H \"AccountKey: YOUR_KEY\" \\\n  https://cloudcdn.pro/api/insights/geography?days=7\n\n# Error tracking\ncurl -H \"AccountKey: YOUR_KEY\" \\\n  https://cloudcdn.pro/api/insights/errors?days=7\n```\n\n### Per-zone filtering\n\nAdd `?zone=akande` to any endpoint to filter analytics for a specific tenant.\n\n### Authentication\n\nInsights accept either **AccountKey** or **AccessKey** — read-only and safe for dashboards."
    },
    {
      "name": "Delivery",
      "description": "## Delivery API\n\nTransform, optimize, and deliver assets at the edge. These endpoints run on Cloudflare's global network — results are cached at 300+ locations worldwide.\n\n### Image Transformation\n\nResize, convert, blur, and sharpen any image on the fly:\n\n```\nhttps://cloudcdn.pro/api/transform?url=/akande/v1/logos/akande.svg&w=400&format=webp&q=85\n```\n\n| Parameter | Range | Description |\n|-----------|-------|-------------|\n| `w` | 1–8192 | Width in pixels |\n| `h` | 1–8192 | Height in pixels |\n| `fit` | cover, contain, fill | Resize behavior |\n| `format` | webp, avif, png, jpeg, auto | Output format |\n| `q` | 1–100 | Quality (lower = smaller file) |\n| `blur` | 1–250 | Gaussian blur radius |\n| `sharpen` | 1–10 | Sharpening amount |\n| `gravity` | center, face, auto | Crop focus point |\n\n### Automatic Format Negotiation\n\nRequest any image without a format — the edge reads the browser's `Accept` header and serves the optimal format (AVIF > WebP > PNG):\n\n```\nhttps://cloudcdn.pro/api/auto?path=/akande/v1/logos/akande\n```\n\n### Signed URLs\n\nProtect premium assets with time-limited, HMAC-signed URLs that expire automatically.\n\n### Video Streaming (HLS)\n\nAdaptive bitrate video via HTTP Live Streaming playlists.\n\n### Cache Purge\n\nInstantly invalidate assets by URL, surrogate tag, or purge everything.\n\n### No authentication required\n\nAll Delivery endpoints are public — they are the URLs your end users hit directly. Rate limits prevent abuse (50,000 transforms/month, 100 purges/day)."
    },
    {
      "name": "AI",
      "description": "## AI Services\n\nSearch and explore your asset catalog using natural language. Powered by Cloudflare Workers AI and Vectorize.\n\n### Semantic Search\n\nFind assets by description, not filename:\n\n```bash\n# Find dark banking backgrounds\ncurl 'https://cloudcdn.pro/api/search?q=dark+blue+banking+background'\n\n# Find minimalist logos\ncurl 'https://cloudcdn.pro/api/search?q=minimalist+logo+svg'\n```\n\nThe engine uses a hybrid approach: vector similarity (Vectorize embeddings) with fuzzy text fallback. Results are scored and ranked by relevance.\n\n### AI Concierge\n\nAn intelligent chat assistant that knows your entire CDN — pricing, setup, performance, compliance, and troubleshooting. Powered by RAG over the knowledge base.\n\n```bash\ncurl -X POST -H \"Content-Type: application/json\" \\\n  -d '{ \"message\": \"How do I set up custom domains?\", \"history\": [] }' \\\n  https://cloudcdn.pro/api/chat\n```\n\n### No authentication required\n\nAI endpoints are public. Rate limits: 1,000 chat queries/month, 100 search requests/minute."
    },
    {
      "name": "Operations",
      "description": "Runtime telemetry and dispatch log inspection."
    },
    {
      "name": "Auth",
      "description": "WebAuthn passkey enrollment, authentication, and scoped API token management."
    },
    {
      "name": "Webhooks",
      "description": "Webhook registration, listing, and revocation."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Data Plane",
      "tags": [
        "Storage",
        "Assets"
      ]
    },
    {
      "name": "Control Plane",
      "tags": [
        "Core",
        "Insights"
      ]
    },
    {
      "name": "Edge Services",
      "tags": [
        "Delivery",
        "AI"
      ]
    },
    {
      "name": "Operations Plane",
      "tags": [
        "Auth",
        "Webhooks",
        "Operations"
      ]
    }
  ],
  "components": {
    "securitySchemes": {
      "AccountKey": {
        "type": "apiKey",
        "in": "header",
        "name": "AccountKey",
        "description": "Administrative API key for core management endpoints (zones, rules, statistics). Set via the ACCOUNT_KEY environment variable."
      },
      "AccessKey": {
        "type": "apiKey",
        "in": "header",
        "name": "AccessKey",
        "description": "Storage and asset access key. Set via the STORAGE_KEY environment variable. Also accepted on Insights endpoints."
      },
      "PurgeKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Purge endpoint API key. Set via the PURGE_KEY environment variable."
      },
      "AnalyticsKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Analytics reporting API key. Set via the ANALYTICS_KEY environment variable."
      },
      "BearerToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "cdnsk_...",
        "description": "Scoped Bearer token issued via POST /api/tokens. Required scopes depend on endpoint."
      },
      "SessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "cdn_session",
        "description": "HMAC-signed session cookie issued by `/api/passkeys/auth/complete` or `POST /dashboard/login`."
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "description": "Standard error response following Microsoft API Guidelines and RFC 9457. Includes machine-readable error code, human-readable message, request tracing, and optional inner error details.",
        "properties": {
          "error": {
            "type": "object",
            "description": "Error object containing structured error details.",
            "properties": {
              "code": {
                "type": "string",
                "description": "Machine-readable error code for programmatic handling.",
                "example": "InvalidParameter"
              },
              "message": {
                "type": "string",
                "description": "Human-readable error description with remediation guidance (150+ characters).",
                "example": "The request body contains invalid JSON and could not be parsed. Verify the payload is well-formed JSON with correct syntax."
              },
              "target": {
                "type": "string",
                "nullable": true,
                "description": "The target of the error (e.g., the field name that caused the error).",
                "example": "url"
              },
              "details": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "description": "Additional error details for validation errors."
              },
              "innererror": {
                "type": "object",
                "nullable": true,
                "description": "Internal error details for debugging (only in non-production)."
              }
            },
            "required": [
              "code",
              "message"
            ]
          },
          "HttpCode": {
            "type": "integer",
            "description": "HTTP status code.",
            "example": 400
          },
          "Message": {
            "type": "string",
            "description": "Human-readable error message (duplicate of error.message for backward compatibility).",
            "example": "Invalid request"
          },
          "requestId": {
            "type": "string",
            "format": "uuid",
            "description": "Unique request identifier for support and debugging.",
            "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of when the error occurred.",
            "example": "2026-04-05T12:00:00.000Z"
          },
          "apiVersion": {
            "type": "string",
            "description": "API version that processed the request.",
            "example": "2026-04-01"
          }
        },
        "required": [
          "error",
          "HttpCode",
          "Message",
          "requestId",
          "timestamp"
        ]
      },
      "JsonErrorResponse": {
        "type": "object",
        "description": "Error envelope returned by endpoints that historically used a flat `{ error: string }` shape (auto, transform, purge, stream, analytics). Since Sprint 11 these endpoints route through legacyErrorJson(), which preserves the original string `error` field for back-compat while additively layering the standard envelope (HttpCode, Message, requestId, timestamp, apiVersion) plus tracing response headers (X-Request-ID, X-API-Version). Some endpoints attach further context fields (e.g. `invalid` array on purge tag-validation errors).",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message, or a machine-readable error code on rate-limit responses (e.g. \"limit_reached\").",
            "example": "Missing required parameter: url"
          },
          "HttpCode": {
            "type": "integer",
            "description": "Mirror of the HTTP status code, for clients that pin to JSON-body parsing.",
            "example": 400
          },
          "Message": {
            "type": "string",
            "description": "Same human-readable text as `error` — Microsoft-Guidelines-style alias kept for envelope consistency with other API responses.",
            "example": "Missing required parameter: url"
          },
          "requestId": {
            "type": "string",
            "format": "uuid",
            "description": "Per-request UUID, also surfaced in the X-Request-ID response header. Use it when reporting an issue so operators can correlate logs."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "ISO-8601 timestamp of when the error response was minted on the edge."
          },
          "apiVersion": {
            "type": "string",
            "description": "Pinned API version string, also surfaced in X-API-Version.",
            "example": "2026-04-01"
          }
        },
        "required": [
          "error",
          "HttpCode",
          "Message"
        ]
      },
      "Pagination": {
        "type": "object",
        "description": "Pagination metadata included in paginated list responses. Provides current page, page size, total item count, and total page count for client-side navigation.",
        "properties": {
          "Page": {
            "type": "integer",
            "description": "Current page number (1-based)",
            "example": 1
          },
          "PerPage": {
            "type": "integer",
            "description": "Number of items per page",
            "example": 50
          },
          "TotalItems": {
            "type": "integer",
            "description": "Total number of items matching the query across all pages",
            "example": 342
          },
          "TotalPages": {
            "type": "integer",
            "description": "Total number of pages available",
            "example": 7
          }
        }
      },
      "AssetEntry": {
        "type": "object",
        "description": "A single asset entry in the catalog. Represents a file stored on the CDN with its name, full path, owning project, category classification, file format, and byte size.",
        "properties": {
          "name": {
            "type": "string",
            "description": "File name including extension",
            "example": "logo.svg"
          },
          "path": {
            "type": "string",
            "description": "Full path within the CDN asset tree",
            "example": "akande/v1/logos/logo.svg"
          },
          "project": {
            "type": "string",
            "description": "Project/zone that owns this asset",
            "example": "akande"
          },
          "category": {
            "type": "string",
            "description": "Asset category (e.g., logos, banners, icons)",
            "example": "logos"
          },
          "format": {
            "type": "string",
            "description": "File format/extension",
            "example": "svg"
          },
          "size": {
            "type": "integer",
            "description": "File size in bytes",
            "example": 4523
          }
        }
      },
      "AssetMetadata": {
        "type": "object",
        "description": "Detailed metadata for a single asset, including CDN delivery URL, transform URL, available format variants, content type, and human-readable size. Used by the asset detail endpoint.",
        "properties": {
          "Path": {
            "type": "string",
            "description": "Full asset path within the CDN tree",
            "example": "akande/v1/logos/logo.svg"
          },
          "Name": {
            "type": "string",
            "description": "File name including extension",
            "example": "logo.svg"
          },
          "Project": {
            "type": "string",
            "description": "Project/zone that owns this asset",
            "example": "akande"
          },
          "Category": {
            "type": "string",
            "description": "Asset category classification",
            "example": "logos"
          },
          "Format": {
            "type": "string",
            "description": "Primary file format/extension",
            "example": "svg"
          },
          "Size": {
            "type": "integer",
            "description": "File size in bytes",
            "example": 4523
          },
          "SizeHuman": {
            "type": "string",
            "description": "Human-readable file size",
            "example": "4.4 KB"
          },
          "ContentType": {
            "type": "string",
            "description": "MIME content type",
            "example": "image/svg+xml"
          },
          "CdnUrl": {
            "type": "string",
            "format": "uri",
            "description": "Direct CDN delivery URL for this asset",
            "example": "https://cloudcdn.pro/akande/v1/logos/logo.svg"
          },
          "TransformUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL to the transform endpoint pre-populated with this asset",
            "example": "https://cloudcdn.pro/api/transform?url=/akande/v1/logos/logo.svg"
          },
          "AvailableFormats": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of format variants available for this asset",
            "example": [
              "svg",
              "png",
              "webp"
            ]
          },
          "DateFetched": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when metadata was retrieved",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "StorageFileEntry": {
        "type": "object",
        "description": "A file or directory entry in the storage system. Uses the Bunny.net-compatible format with GUID, storage zone info, path, size, timestamps, and directory flag for recursive listing.",
        "properties": {
          "Guid": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier for this storage entry",
            "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
          },
          "StorageZoneName": {
            "type": "string",
            "description": "Name of the storage zone containing this entry",
            "example": "cloudcdn"
          },
          "Path": {
            "type": "string",
            "description": "Directory path within the storage zone (always ends with /)",
            "example": "/clients/akande/v1/logos/"
          },
          "ObjectName": {
            "type": "string",
            "description": "File or directory name",
            "example": "logo.svg"
          },
          "Length": {
            "type": "integer",
            "description": "File size in bytes (0 for directories)",
            "example": 4523
          },
          "LastChanged": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the last modification",
            "example": "2026-04-04T12:00:00.000Z"
          },
          "ServerId": {
            "type": "integer",
            "description": "Internal server identifier (always 0 for GitOps storage)",
            "example": 0
          },
          "ArrayNumber": {
            "type": "integer",
            "description": "Internal array number (always 0 for GitOps storage)",
            "example": 0
          },
          "IsDirectory": {
            "type": "boolean",
            "description": "Whether this entry represents a directory rather than a file",
            "example": false
          },
          "UserId": {
            "type": "string",
            "description": "Owning user/storage zone identifier",
            "example": "cloudcdn"
          },
          "ContentType": {
            "type": "string",
            "description": "MIME content type (empty string for directories)",
            "example": ""
          },
          "DateCreated": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the file was first created",
            "example": "2026-04-04T12:00:00.000Z"
          },
          "StorageZoneId": {
            "type": "integer",
            "description": "Numeric storage zone identifier (always 0 for GitOps storage)",
            "example": 0
          },
          "Checksum": {
            "type": [
              "string",
              "null"
            ],
            "description": "SHA-256 checksum of the file contents, or null if not computed",
            "example": null
          },
          "ReplicatedZones": {
            "type": "string",
            "description": "Comma-separated list of replication zones (empty for single-region)",
            "example": ""
          }
        }
      },
      "UploadResponse": {
        "type": "object",
        "description": "Response returned after a successful file upload. Contains the committed file path, size, optional checksum, creation timestamp, and edge deployment status.",
        "properties": {
          "HttpCode": {
            "type": "integer",
            "description": "HTTP status code (201 for successful upload)",
            "example": 201
          },
          "Message": {
            "type": "string",
            "description": "Human-readable success message",
            "example": "File uploaded successfully"
          },
          "Path": {
            "type": "string",
            "description": "Committed file path within the storage tree",
            "example": "akande/v1/logos/new-logo.svg"
          },
          "Length": {
            "type": "integer",
            "description": "File size in bytes",
            "example": 8192
          },
          "Checksum": {
            "type": [
              "string",
              "null"
            ],
            "description": "SHA-256 checksum if provided in the request, otherwise null",
            "example": null
          },
          "DateCreated": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the file was committed",
            "example": "2026-04-04T12:00:00.000Z"
          },
          "EdgeStatus": {
            "type": "string",
            "enum": [
              "pending",
              "purging"
            ],
            "description": "Edge deployment status: pending (new file) or purging (overwrite triggering cache invalidation)",
            "example": "pending"
          },
          "EdgeNote": {
            "type": "string",
            "description": "Informational note about edge availability timeline",
            "example": "File committed to repository. It will be available at the edge after the CI/CD pipeline deploys (~60-90 seconds)."
          }
        }
      },
      "DeleteResponse": {
        "type": "object",
        "description": "Response returned after a successful file deletion. Includes the removed file path and edge cache purge status.",
        "properties": {
          "HttpCode": {
            "type": "integer",
            "description": "HTTP status code (200 for successful deletion)",
            "example": 200
          },
          "Message": {
            "type": "string",
            "description": "Human-readable success message",
            "example": "File deleted successfully"
          },
          "Path": {
            "type": "string",
            "description": "Path of the deleted file",
            "example": "akande/v1/logos/old-logo.svg"
          },
          "EdgeStatus": {
            "type": "string",
            "enum": [
              "pending",
              "purging"
            ],
            "description": "Edge cache purge status (always purging for deletes)",
            "example": "purging"
          },
          "EdgeNote": {
            "type": "string",
            "description": "Informational note about edge cache purge timeline",
            "example": "File removed from repository and edge cache purge initiated."
          }
        }
      },
      "BatchUploadRequest": {
        "type": "object",
        "description": "Request body for batch file upload. Contains an array of up to 50 files, each with a destination path, content (base64 or UTF-8 encoded), and optional encoding specification.",
        "required": [
          "files"
        ],
        "properties": {
          "files": {
            "type": "array",
            "maxItems": 50,
            "description": "Array of files to upload in a single atomic Git commit",
            "items": {
              "type": "object",
              "required": [
                "path",
                "content"
              ],
              "properties": {
                "path": {
                  "type": "string",
                  "description": "Destination path in the repository",
                  "example": "clients/akande/v1/logos/new.svg"
                },
                "content": {
                  "type": "string",
                  "description": "File content (base64 encoded by default)",
                  "example": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg=="
                },
                "encoding": {
                  "type": "string",
                  "enum": [
                    "base64",
                    "utf-8"
                  ],
                  "default": "base64",
                  "description": "Content encoding"
                }
              }
            }
          }
        }
      },
      "BatchUploadResponse": {
        "type": "object",
        "description": "Response returned after a successful batch upload. Contains the Git commit SHA, list of committed file paths, and edge deployment status for the entire batch.",
        "properties": {
          "HttpCode": {
            "type": "integer",
            "description": "HTTP status code (201 for successful batch upload)",
            "example": 201
          },
          "Message": {
            "type": "string",
            "description": "Human-readable success message with file count",
            "example": "3 file(s) uploaded in a single commit"
          },
          "Commit": {
            "type": "string",
            "description": "Git commit SHA for the batch operation",
            "example": "abc123def456"
          },
          "Files": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of file paths that were committed",
            "example": [
              "clients/akande/v1/logos/a.svg",
              "clients/akande/v1/logos/b.svg"
            ]
          },
          "EdgeStatus": {
            "type": "string",
            "description": "Edge deployment status for the batch",
            "example": "pending"
          },
          "EdgeNote": {
            "type": "string",
            "description": "Informational note about edge availability timeline",
            "example": "Files committed. Available at the edge after CI/CD deploy (~60-90 seconds)."
          },
          "DateCreated": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the batch commit was created",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "Zone": {
        "type": "object",
        "description": "Summary representation of a tenant zone (client project). Contains zone identity, storage zone binding, origin URL, aggregate file count and storage usage, asset categories, and operational status.",
        "properties": {
          "Id": {
            "type": "string",
            "description": "Unique zone identifier (same as the project name)",
            "example": "akande"
          },
          "Name": {
            "type": "string",
            "description": "Human-readable zone name",
            "example": "akande"
          },
          "StorageZoneName": {
            "type": "string",
            "description": "Name of the backing storage zone",
            "example": "cloudcdn"
          },
          "OriginUrl": {
            "type": "string",
            "format": "uri",
            "description": "CDN origin URL for this zone",
            "example": "https://cloudcdn.pro/akande/"
          },
          "FileCount": {
            "type": "integer",
            "description": "Total number of files in the zone",
            "example": 45
          },
          "StorageUsed": {
            "type": "integer",
            "description": "Total storage in bytes",
            "example": 2457600
          },
          "StorageUsedHuman": {
            "type": "string",
            "description": "Human-readable total storage size",
            "example": "2.3 MB"
          },
          "Categories": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Distinct asset categories present in the zone",
            "example": [
              "banners",
              "icons",
              "logos"
            ]
          },
          "DateCreated": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the zone was created",
            "example": "2026-04-04T12:00:00.000Z"
          },
          "Enabled": {
            "type": "boolean",
            "description": "Whether the zone is currently enabled for serving",
            "example": true
          },
          "Suspended": {
            "type": "boolean",
            "description": "Whether the zone has been suspended (e.g., for abuse)",
            "example": false
          }
        }
      },
      "ZoneDetail": {
        "type": "object",
        "description": "Detailed zone representation including the full file listing, available formats, and all categories. Extends the Zone summary with per-file metadata for administrative use.",
        "properties": {
          "Id": {
            "type": "string",
            "description": "Unique zone identifier",
            "example": "akande"
          },
          "Name": {
            "type": "string",
            "description": "Human-readable zone name",
            "example": "akande"
          },
          "StorageZoneName": {
            "type": "string",
            "description": "Name of the backing storage zone",
            "example": "cloudcdn"
          },
          "OriginUrl": {
            "type": "string",
            "format": "uri",
            "description": "CDN origin URL for this zone",
            "example": "https://cloudcdn.pro/akande/"
          },
          "FileCount": {
            "type": "integer",
            "description": "Total number of files in the zone",
            "example": 45
          },
          "StorageUsed": {
            "type": "integer",
            "description": "Total storage in bytes",
            "example": 2457600
          },
          "StorageUsedHuman": {
            "type": "string",
            "description": "Human-readable total storage size",
            "example": "2.3 MB"
          },
          "Categories": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Distinct asset categories present in the zone",
            "example": [
              "banners",
              "icons",
              "logos"
            ]
          },
          "Formats": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Distinct file formats present in the zone",
            "example": [
              "png",
              "svg",
              "webp"
            ]
          },
          "Files": {
            "type": "array",
            "description": "Complete list of files in the zone with per-file metadata",
            "items": {
              "type": "object",
              "description": "Individual file entry within a zone detail listing",
              "properties": {
                "Path": {
                  "type": "string",
                  "description": "Full file path within the CDN tree"
                },
                "Name": {
                  "type": "string",
                  "description": "File name including extension"
                },
                "Format": {
                  "type": "string",
                  "description": "File format/extension"
                },
                "Size": {
                  "type": "integer",
                  "description": "File size in bytes"
                },
                "Category": {
                  "type": "string",
                  "description": "Asset category classification"
                }
              }
            }
          },
          "Enabled": {
            "type": "boolean",
            "description": "Whether the zone is currently enabled for serving",
            "example": true
          },
          "Suspended": {
            "type": "boolean",
            "description": "Whether the zone has been suspended",
            "example": false
          },
          "DateCreated": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the zone was created",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "ZoneCreateRequest": {
        "type": "object",
        "description": "Request body for creating a new tenant zone. The zone name must be 2-64 lowercase alphanumeric characters with hyphens, and must not already exist.",
        "required": [
          "Name"
        ],
        "properties": {
          "Name": {
            "type": "string",
            "description": "Zone name: 2-64 alphanumeric characters with hyphens",
            "pattern": "^[a-z0-9-]{2,64}$",
            "example": "newclient"
          }
        }
      },
      "ZoneCreateResponse": {
        "type": "object",
        "description": "Response returned after a successful zone creation. Includes the Git commit SHA, scaffolded directories, and edge deployment status.",
        "properties": {
          "HttpCode": {
            "type": "integer",
            "description": "HTTP status code (201 for successful creation)",
            "example": 201
          },
          "Message": {
            "type": "string",
            "description": "Human-readable success message",
            "example": "Zone 'newclient' created successfully"
          },
          "Id": {
            "type": "string",
            "description": "Unique zone identifier",
            "example": "newclient"
          },
          "Name": {
            "type": "string",
            "description": "Zone name",
            "example": "newclient"
          },
          "OriginUrl": {
            "type": "string",
            "format": "uri",
            "description": "CDN origin URL for the new zone",
            "example": "https://cloudcdn.pro/newclient/"
          },
          "Commit": {
            "type": "string",
            "description": "Git commit SHA for the zone creation",
            "example": "abc123def456"
          },
          "Directories": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Standard v1/ directories scaffolded for the new zone",
            "example": [
              "banners",
              "github",
              "icons",
              "logos",
              "titles"
            ]
          },
          "EdgeStatus": {
            "type": "string",
            "description": "Edge deployment status",
            "example": "pending"
          },
          "EdgeNote": {
            "type": "string",
            "description": "Informational note about edge availability timeline",
            "example": "Zone will be live after CI/CD deploy (~60-90 seconds)."
          },
          "DateCreated": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the zone was created",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "ZoneDeleteResponse": {
        "type": "object",
        "description": "Response returned after a successful zone deletion. Includes the Git commit SHA, number of files removed, and edge cache purge status.",
        "properties": {
          "HttpCode": {
            "type": "integer",
            "description": "HTTP status code (200 for successful deletion)",
            "example": 200
          },
          "Message": {
            "type": "string",
            "description": "Human-readable success message with file removal count",
            "example": "Zone 'oldclient' deleted (12 files removed)"
          },
          "Commit": {
            "type": "string",
            "description": "Git commit SHA for the deletion",
            "example": "abc123def456"
          },
          "FilesRemoved": {
            "type": "integer",
            "description": "Number of files removed in the deletion",
            "example": 12
          },
          "EdgeStatus": {
            "type": "string",
            "description": "Edge cache purge status (always purging for zone deletes)",
            "example": "purging"
          }
        }
      },
      "DomainAddRequest": {
        "type": "object",
        "description": "Request body for adding a custom domain to a zone. The hostname must be a fully qualified domain name with a CNAME record pointing to cloudcdn-pro.pages.dev.",
        "required": [
          "Hostname"
        ],
        "properties": {
          "Hostname": {
            "type": "string",
            "description": "Fully qualified domain name",
            "example": "cdn.akande.com"
          }
        }
      },
      "DomainAddResponse": {
        "type": "object",
        "description": "Response returned after successfully adding a custom domain to a zone. Includes SSL provisioning status and CNAME configuration instructions.",
        "properties": {
          "HttpCode": {
            "type": "integer",
            "description": "HTTP status code (201 for successful domain addition)",
            "example": 201
          },
          "Message": {
            "type": "string",
            "description": "Human-readable success message",
            "example": "Custom domain 'cdn.akande.com' added successfully"
          },
          "Zone": {
            "type": "string",
            "description": "Zone the domain was added to",
            "example": "akande"
          },
          "Hostname": {
            "type": "string",
            "description": "The custom domain hostname that was added",
            "example": "cdn.akande.com"
          },
          "SslStatus": {
            "type": "string",
            "description": "SSL certificate provisioning status",
            "example": "provisioning"
          },
          "Note": {
            "type": "string",
            "description": "Instructions for DNS configuration",
            "example": "SSL certificate will be provisioned automatically. Point your CNAME to cloudcdn-pro.pages.dev."
          },
          "DateCreated": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the domain was added",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "StatisticsResponse": {
        "type": "object",
        "description": "Comprehensive edge statistics response including request counts, bandwidth, cache ratios, top assets, and geographic distribution over the specified time period.",
        "properties": {
          "Period": {
            "type": "object",
            "description": "Time period and scope of the statistics",
            "properties": {
              "Days": {
                "type": "integer",
                "description": "Number of days included in the report",
                "example": 7
              },
              "Zone": {
                "type": "string",
                "description": "Zone filter applied (or 'all' for aggregate)",
                "example": "all"
              }
            }
          },
          "Summary": {
            "type": "object",
            "description": "Aggregate summary metrics for the period",
            "properties": {
              "TotalRequests": {
                "type": "integer",
                "description": "Total number of requests served",
                "example": 125000
              },
              "TotalBandwidth": {
                "type": "integer",
                "description": "Total bandwidth in bytes",
                "example": 5368709120
              },
              "TotalBandwidthHuman": {
                "type": "string",
                "description": "Human-readable total bandwidth",
                "example": "5.00 GB"
              },
              "CacheHitRate": {
                "type": "string",
                "description": "Percentage of requests served from cache",
                "example": "94.2%"
              },
              "UniqueCountries": {
                "type": "integer",
                "description": "Number of distinct countries that sent requests",
                "example": 42
              }
            }
          },
          "Daily": {
            "type": "array",
            "description": "Per-day breakdown of request and bandwidth metrics",
            "items": {
              "type": "object",
              "description": "Daily statistics for a single day",
              "properties": {
                "Date": {
                  "type": "string",
                  "format": "date",
                  "description": "Date in ISO 8601 format",
                  "example": "2026-04-03"
                },
                "TotalRequests": {
                  "type": "integer",
                  "description": "Total requests on this day",
                  "example": 18000
                },
                "Bandwidth": {
                  "type": "integer",
                  "description": "Bandwidth in bytes on this day",
                  "example": 768000000
                },
                "BandwidthHuman": {
                  "type": "string",
                  "description": "Human-readable bandwidth for this day",
                  "example": "732.4 MB"
                },
                "CacheHit": {
                  "type": "integer",
                  "description": "Number of cache hits on this day",
                  "example": 17000
                },
                "CacheMiss": {
                  "type": "integer",
                  "description": "Number of cache misses on this day",
                  "example": 1000
                }
              }
            }
          },
          "TopAssets": {
            "type": "array",
            "description": "Most-requested assets ranked by request count",
            "items": {
              "type": "object",
              "description": "A top asset entry with path and request count",
              "properties": {
                "Path": {
                  "type": "string",
                  "description": "Asset path",
                  "example": "/akande/v1/logos/logo.svg"
                },
                "Requests": {
                  "type": "integer",
                  "description": "Total request count for this asset",
                  "example": 5400
                }
              }
            }
          },
          "GeoDistribution": {
            "type": "array",
            "description": "Request counts by country, sorted descending by volume",
            "items": {
              "type": "object",
              "description": "Geographic distribution entry with country code and request count",
              "properties": {
                "CountryCode": {
                  "type": "string",
                  "description": "ISO 3166-1 alpha-2 country code",
                  "example": "US"
                },
                "Requests": {
                  "type": "integer",
                  "description": "Total requests from this country",
                  "example": 45000
                }
              }
            }
          }
        }
      },
      "RulesResponse": {
        "type": "object",
        "description": "Current edge rules configuration containing the contents of _headers and _redirects files, the list of editable rule files, and a fetch timestamp.",
        "properties": {
          "Headers": {
            "type": [
              "string",
              "null"
            ],
            "description": "Contents of the _headers file",
            "example": "/*.webp\n  Cache-Control: public, max-age=31536000, immutable"
          },
          "Redirects": {
            "type": [
              "string",
              "null"
            ],
            "description": "Contents of the _redirects file",
            "example": "/old-path /new-path 301"
          },
          "Editable": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of rule files that can be edited",
            "example": [
              "_headers",
              "_redirects"
            ]
          },
          "DateFetched": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the rules were fetched from the repository",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "RulesUpdateRequest": {
        "type": "object",
        "description": "Request body for updating an edge rule file. Specifies which file to update (_headers or _redirects) and the new content (max 100 KB).",
        "required": [
          "File",
          "Content"
        ],
        "properties": {
          "File": {
            "type": "string",
            "enum": [
              "_headers",
              "_redirects"
            ],
            "description": "The edge rule file to update",
            "example": "_headers"
          },
          "Content": {
            "type": "string",
            "maxLength": 100000,
            "description": "New file content (max 100KB)",
            "example": "/*.webp\n  Cache-Control: public, max-age=31536000, immutable"
          }
        }
      },
      "RulesUpdateResponse": {
        "type": "object",
        "description": "Response returned after a successful edge rules update. Includes the Git commit SHA and edge deployment status.",
        "properties": {
          "HttpCode": {
            "type": "integer",
            "description": "HTTP status code (200 for successful update)",
            "example": 200
          },
          "Message": {
            "type": "string",
            "description": "Human-readable success message",
            "example": "_headers updated successfully"
          },
          "File": {
            "type": "string",
            "description": "Name of the updated rule file",
            "example": "_headers"
          },
          "Commit": {
            "type": "string",
            "description": "Git commit SHA for the update",
            "example": "abc123def456"
          },
          "EdgeStatus": {
            "type": "string",
            "description": "Edge deployment status",
            "example": "pending"
          },
          "EdgeNote": {
            "type": "string",
            "description": "Informational note about when changes take effect",
            "example": "Edge rules will take effect after CI/CD deploy (~60-90 seconds)."
          },
          "DateModified": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the rules were updated",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "InsightsSummaryResponse": {
        "type": "object",
        "description": "Aggregate analytics summary providing total requests, bandwidth, cache hit rate, and unique country count for the specified time period and optional zone filter.",
        "properties": {
          "Period": {
            "type": "object",
            "description": "Time period and scope of the summary",
            "properties": {
              "Days": {
                "type": "integer",
                "description": "Number of days included in the summary",
                "example": 7
              },
              "Zone": {
                "type": "string",
                "description": "Zone filter applied (or 'all' for aggregate)",
                "example": "all"
              }
            }
          },
          "TotalRequests": {
            "type": "integer",
            "description": "Total number of requests served during the period",
            "example": 125000
          },
          "TotalBandwidth": {
            "type": "string",
            "description": "Human-readable total bandwidth",
            "example": "5.00 GB"
          },
          "TotalBandwidthBytes": {
            "type": "integer",
            "description": "Total bandwidth in bytes",
            "example": 5368709120
          },
          "CacheHitRate": {
            "type": "string",
            "description": "Percentage of requests served from cache",
            "example": "94.2%"
          },
          "UniqueCountries": {
            "type": "integer",
            "description": "Number of distinct countries that sent requests",
            "example": 42
          },
          "DateFetched": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the summary was generated",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "TopAssetsResponse": {
        "type": "object",
        "description": "Response containing the most-requested assets over the specified period, ranked by request count descending.",
        "properties": {
          "Period": {
            "type": "object",
            "description": "Time period of the report",
            "properties": {
              "Days": {
                "type": "integer",
                "description": "Number of days included in the report",
                "example": 7
              }
            }
          },
          "Assets": {
            "type": "array",
            "description": "Ranked list of top assets by request count",
            "items": {
              "type": "object",
              "description": "A top asset entry with its path and total request count",
              "properties": {
                "Path": {
                  "type": "string",
                  "description": "Asset path",
                  "example": "/akande/v1/logos/logo.svg"
                },
                "Requests": {
                  "type": "integer",
                  "description": "Total request count",
                  "example": 5400
                }
              }
            }
          },
          "DateFetched": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the report was generated",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "GeographyResponse": {
        "type": "object",
        "description": "Geographic distribution of requests over the specified period. Each entry contains an ISO 3166-1 alpha-2 country code and the request count from that country.",
        "properties": {
          "Period": {
            "type": "object",
            "description": "Time period of the report",
            "properties": {
              "Days": {
                "type": "integer",
                "description": "Number of days included in the report",
                "example": 7
              }
            }
          },
          "Countries": {
            "type": "array",
            "description": "Request counts by country, sorted descending by volume",
            "items": {
              "type": "object",
              "description": "Country-level request count entry",
              "properties": {
                "CountryCode": {
                  "type": "string",
                  "description": "ISO 3166-1 alpha-2 country code",
                  "example": "US"
                },
                "Requests": {
                  "type": "integer",
                  "description": "Total requests from this country",
                  "example": 45000
                }
              }
            }
          },
          "DateFetched": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the report was generated",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "ErrorsResponse": {
        "type": "object",
        "description": "Error tracking report showing 4xx/5xx error counts grouped by HTTP status code, with the top paths generating each error type over the specified period.",
        "properties": {
          "Period": {
            "type": "object",
            "description": "Time period of the report",
            "properties": {
              "Days": {
                "type": "integer",
                "description": "Number of days included in the report",
                "example": 7
              }
            }
          },
          "Errors": {
            "type": "array",
            "description": "Error groups, each containing a status code, total count, and top offending paths",
            "items": {
              "type": "object",
              "description": "Error group for a single HTTP status code",
              "properties": {
                "StatusCode": {
                  "type": "integer",
                  "description": "HTTP error status code (4xx or 5xx)",
                  "example": 404
                },
                "Count": {
                  "type": "integer",
                  "description": "Total number of errors with this status code",
                  "example": 230
                },
                "TopPaths": {
                  "type": "array",
                  "description": "Top 10 paths generating this error",
                  "items": {
                    "type": "object",
                    "description": "A path that generated errors with its count",
                    "properties": {
                      "Path": {
                        "type": "string",
                        "description": "Request path that triggered the error",
                        "example": "/missing/asset.png"
                      },
                      "Count": {
                        "type": "integer",
                        "description": "Number of errors for this path",
                        "example": 50
                      }
                    }
                  }
                }
              }
            }
          },
          "Note": {
            "type": "string",
            "description": "Informational note when no errors are tracked",
            "example": "Error tracking populates automatically from middleware analytics."
          },
          "DateFetched": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the report was generated",
            "example": "2026-04-04T12:00:00.000Z"
          }
        }
      },
      "PurgeRequest": {
        "type": "object",
        "description": "Cache purge request. Exactly one of urls, tags, or purge_everything must be specified per request. URLs must start with https://cloudcdn.pro/.",
        "properties": {
          "urls": {
            "type": "array",
            "maxItems": 30,
            "items": {
              "type": "string",
              "format": "uri"
            },
            "description": "Up to 30 URLs to purge. Must start with https://cloudcdn.pro/.",
            "example": [
              "https://cloudcdn.pro/akande/v1/logos/logo.svg"
            ]
          },
          "tags": {
            "type": "array",
            "maxItems": 30,
            "items": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9-]+$"
            },
            "description": "Up to 30 cache tags to purge. Alphanumeric with hyphens only.",
            "example": [
              "project-akande",
              "type-banner"
            ]
          },
          "purge_everything": {
            "type": "boolean",
            "description": "Set to true to purge the entire cache.",
            "example": true
          }
        }
      },
      "PurgeResponse": {
        "type": "object",
        "description": "Response returned after a successful cache purge operation. Contains the purged targets, remaining daily purge quota, and the raw Cloudflare API response.",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the purge operation succeeded",
            "example": true
          },
          "purged": {
            "description": "The URLs, tags, or \"everything\" that was purged",
            "example": [
              "https://cloudcdn.pro/akande/v1/logos/logo.svg"
            ]
          },
          "remaining_today": {
            "type": "integer",
            "description": "Remaining purge requests allowed today",
            "example": 95
          },
          "cloudflare": {
            "type": "object",
            "description": "Raw Cloudflare API response for debugging"
          }
        }
      },
      "AnalyticsReportResponse": {
        "type": "object",
        "description": "Daily analytics report with per-day breakdowns of hits, bandwidth, top assets, geographic distribution, and cache ratios. Data is retained in KV for up to 35 days.",
        "properties": {
          "days": {
            "type": "integer",
            "description": "Number of days included in the report",
            "example": 7
          },
          "data": {
            "type": "array",
            "description": "Per-day analytics entries",
            "items": {
              "type": "object",
              "description": "Analytics data for a single day",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date",
                  "description": "Date in ISO 8601 format",
                  "example": "2026-04-03"
                },
                "hits": {
                  "type": "integer",
                  "description": "Total request hits on this day",
                  "example": 18000
                },
                "bandwidth": {
                  "type": "object",
                  "description": "Bandwidth usage for this day",
                  "properties": {
                    "bytes": {
                      "type": "integer",
                      "description": "Bandwidth in bytes",
                      "example": 768000000
                    },
                    "human": {
                      "type": "string",
                      "description": "Human-readable bandwidth",
                      "example": "732.42 MB"
                    }
                  }
                },
                "top_assets": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "integer"
                  },
                  "description": "Map of asset paths to their request counts for this day",
                  "example": {
                    "/akande/v1/logos/logo.svg": 1200
                  }
                },
                "geo": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "integer"
                  },
                  "description": "Map of country codes to their request counts for this day",
                  "example": {
                    "US": 8000,
                    "DE": 3000
                  }
                },
                "cache": {
                  "type": "object",
                  "description": "Cache performance metrics for this day",
                  "properties": {
                    "hit": {
                      "type": "integer",
                      "description": "Number of cache hits",
                      "example": 17000
                    },
                    "miss": {
                      "type": "integer",
                      "description": "Number of cache misses",
                      "example": 1000
                    },
                    "ratio": {
                      "type": "string",
                      "description": "Cache hit ratio as a percentage string",
                      "example": "94.4%"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "AnalyticsTrackRequest": {
        "type": "object",
        "description": "Request body for recording a single analytics hit. Typically called by edge middleware to increment daily counters for hits, bandwidth, top assets, geo, and cache status.",
        "properties": {
          "path": {
            "type": "string",
            "description": "Request path to record",
            "example": "/akande/v1/logos/logo.svg"
          },
          "bytes": {
            "type": "integer",
            "description": "Response body size in bytes",
            "example": 4523
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code",
            "example": "US"
          },
          "cache": {
            "type": "string",
            "enum": [
              "HIT",
              "MISS"
            ],
            "description": "Cache status",
            "example": "HIT"
          }
        }
      },
      "SearchResponse": {
        "type": "object",
        "description": "Semantic search results containing matched assets with relevance scores. Results are ranked by score descending, with vector search yielding scores 0.5-1.0 and fuzzy fallback yielding fractional scores.",
        "properties": {
          "results": {
            "type": "array",
            "description": "Matched assets ranked by relevance score",
            "items": {
              "type": "object",
              "description": "A single search result with asset metadata and relevance score",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "File name including extension",
                  "example": "logo.svg"
                },
                "path": {
                  "type": "string",
                  "description": "Full asset path within the CDN tree",
                  "example": "akande/v1/logos/logo.svg"
                },
                "project": {
                  "type": "string",
                  "description": "Project/zone that owns this asset",
                  "example": "akande"
                },
                "category": {
                  "type": "string",
                  "description": "Asset category classification",
                  "example": "logos"
                },
                "format": {
                  "type": "string",
                  "description": "File format/extension",
                  "example": "svg"
                },
                "size": {
                  "type": "integer",
                  "description": "File size in bytes",
                  "example": 4523
                },
                "score": {
                  "type": "number",
                  "description": "Relevance score (0-1). Higher from vector search, fractional from fuzzy.",
                  "example": 0.847
                }
              }
            }
          },
          "query": {
            "type": "string",
            "description": "Original search query",
            "example": "dark blue banking background"
          },
          "count": {
            "type": "integer",
            "description": "Number of results returned",
            "example": 5
          }
        }
      },
      "ChatRequest": {
        "type": "object",
        "description": "Request body for the AI Chat Concierge. Contains the user's message and optional conversation history (last 5 turns are used for context).",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "User message to the concierge",
            "example": "What image formats does CloudCDN support?"
          },
          "history": {
            "type": "array",
            "description": "Previous conversation turns (last 5 are used)",
            "items": {
              "type": "object",
              "description": "A single conversation turn with role and content",
              "required": [
                "role",
                "content"
              ],
              "properties": {
                "role": {
                  "type": "string",
                  "enum": [
                    "user",
                    "assistant"
                  ],
                  "description": "Speaker role: user or assistant",
                  "example": "user"
                },
                "content": {
                  "type": "string",
                  "description": "Message content for this turn",
                  "example": "Tell me about pricing"
                }
              }
            }
          }
        }
      },
      "AltTextResponse": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "alt": {
            "type": "string",
            "description": "Accessibility-quality description, ≤160 chars."
          },
          "model": {
            "type": "string",
            "example": "@cf/llava-hf/llava-1.5-7b-hf"
          },
          "source": {
            "type": "string",
            "enum": [
              "ai",
              "cached"
            ]
          },
          "degraded": {
            "type": "boolean"
          },
          "dateGenerated": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Response from /api/ai/alt-text: AI-generated alt text plus source-of-truth metadata."
      },
      "SmartCropResponse": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "gravity": {
            "type": "string",
            "enum": [
              "center",
              "north",
              "south",
              "east",
              "west",
              "northeast",
              "northwest",
              "southeast",
              "southwest",
              "face"
            ]
          },
          "confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "model": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "ai",
              "cached"
            ]
          },
          "degraded": {
            "type": "boolean"
          },
          "dateGenerated": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Response from /api/ai/smart-crop: subject-aware gravity directive compatible with /api/transform."
      },
      "ModerationResponse": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "safe": {
            "type": "boolean"
          },
          "verdict": {
            "type": "string",
            "enum": [
              "safe",
              "borderline",
              "unsafe"
            ]
          },
          "categories": {
            "type": "object",
            "properties": {
              "nudity": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "violence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "drugs": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "hateSymbols": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "gore": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              }
            }
          },
          "reasoning": {
            "type": "string",
            "maxLength": 240
          },
          "model": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "ai",
              "cached"
            ]
          },
          "degraded": {
            "type": "boolean"
          },
          "dateGenerated": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Response from /api/ai/moderate: structured safe-search verdict plus per-category 0-1 scores."
      },
      "LqipResponse": {
        "type": "object",
        "properties": {
          "lqip": {
            "type": "string",
            "description": "Data URI: data:image/webp;base64,..."
          },
          "bytes": {
            "type": "integer"
          },
          "width": {
            "type": "integer"
          },
          "dateGenerated": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Response from /api/lqip: base64 data URI for an inline low-quality image placeholder."
      },
      "BlurhashResponse": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "hash": {
            "type": "string",
            "description": "40-char hex SHA-256 prefix.",
            "pattern": "^[0-9a-f]{40}$"
          },
          "dataUri": {
            "type": "string"
          },
          "width": {
            "type": "integer"
          },
          "bytes": {
            "type": "integer"
          },
          "source": {
            "type": "string",
            "enum": [
              "fresh",
              "cached"
            ]
          },
          "dateGenerated": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Response from /api/blurhash: content-addressable placeholder hash plus data URI."
      },
      "AssetInsightsResponse": {
        "type": "object",
        "properties": {
          "Path": {
            "type": "string"
          },
          "Period": {
            "type": "object",
            "properties": {
              "Days": {
                "type": "integer"
              }
            }
          },
          "TotalRequests": {
            "type": "integer"
          },
          "Errors": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            },
            "description": "Map of HTTP status code → count over the window."
          },
          "Daily": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "Date": {
                  "type": "string",
                  "format": "date"
                },
                "Requests": {
                  "type": "integer"
                },
                "Errors": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "DateFetched": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Response from /api/insights/asset: daily request counts and error roll-ups for one asset."
      },
      "AuditLogResponse": {
        "type": "object",
        "properties": {
          "Period": {
            "type": "object",
            "properties": {
              "Days": {
                "type": "integer"
              },
              "Action": {
                "type": "string",
                "nullable": true
              },
              "Limit": {
                "type": "integer"
              }
            }
          },
          "Entries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "timestamp": {
                  "type": "string",
                  "format": "date-time"
                },
                "action": {
                  "type": "string"
                },
                "ip": {
                  "type": "string"
                },
                "userAgent": {
                  "type": "string",
                  "maxLength": 256
                },
                "requestId": {
                  "type": "string",
                  "nullable": true
                },
                "meta": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "Count": {
            "type": "integer"
          },
          "DateFetched": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Response from /api/core/audit-logs: persistent audit trail entries (90-day retention)."
      },
      "HealthResponse": {
        "type": "object",
        "description": "Service health summary, including per-binding probe results when `?deep=1` is set.",
        "required": [
          "status",
          "timestamp",
          "apiVersion",
          "bindings",
          "checks"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded"
            ],
            "description": "Overall service status."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "apiVersion": {
            "type": "string"
          },
          "bindings": {
            "type": "object",
            "description": "Boolean presence of each Cloudflare binding.",
            "properties": {
              "assets": {
                "type": "boolean"
              },
              "kv": {
                "type": "boolean"
              },
              "ai": {
                "type": "boolean"
              },
              "vectorize": {
                "type": "boolean"
              },
              "rateLimiter": {
                "type": "boolean"
              },
              "metrics": {
                "type": "boolean"
              },
              "webhookQueue": {
                "type": "boolean"
              },
              "auditLogKv": {
                "type": "boolean"
              }
            }
          },
          "checks": {
            "type": "array",
            "description": "Per-binding probe results.",
            "items": {
              "type": "object",
              "required": [
                "name",
                "configured",
                "healthy",
                "method"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "configured": {
                  "type": "boolean"
                },
                "healthy": {
                  "type": "boolean"
                },
                "method": {
                  "type": "string",
                  "enum": [
                    "shape",
                    "manifest-fetch",
                    "kv-get"
                  ]
                },
                "latencyMs": {
                  "type": "integer",
                  "description": "Round-trip latency (only present for I/O probes)."
                },
                "optional": {
                  "type": "boolean",
                  "description": "When true, missing-but-configured doesn't degrade the service."
                },
                "error": {
                  "type": "string",
                  "description": "Failure reason when healthy=false."
                }
              }
            }
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid credentials.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "BadRequest": {
        "description": "Request validation failed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/assets": {
      "get": {
        "operationId": "listAssets",
        "summary": "List assets",
        "description": "Paginated, filterable asset catalog. Streams JSON for sub-2ms TTFB. Supports filtering by project, category, format, and free-text search. Rate limit: none (public with AccessKey).",
        "tags": [
          "Assets"
        ],
        "security": [
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "project",
            "in": "query",
            "description": "Filter by project/zone name",
            "schema": {
              "type": "string"
            },
            "example": "akande"
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by asset category (e.g., logos, banners, icons)",
            "schema": {
              "type": "string"
            },
            "example": "logos"
          },
          {
            "name": "format",
            "in": "query",
            "description": "Filter by file format",
            "schema": {
              "type": "string"
            },
            "example": "svg"
          },
          {
            "name": "q",
            "in": "query",
            "description": "Free-text search against name and path (case-insensitive substring match)",
            "schema": {
              "type": "string"
            },
            "example": "banner"
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number (1-based)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "example": 1
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Items per page (1-200)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "example": 50
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort field",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "size",
                "project"
              ],
              "default": "name"
            },
            "example": "name"
          },
          {
            "name": "order",
            "in": "query",
            "description": "Sort direction",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "asc"
            },
            "example": "asc"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated asset list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "Pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    },
                    "Filters": {
                      "type": "object",
                      "properties": {
                        "Project": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "Category": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "Format": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "Query": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    "DateFetched": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "Data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AssetEntry"
                      }
                    }
                  }
                },
                "example": {
                  "Pagination": {
                    "Page": 1,
                    "PerPage": 50,
                    "TotalItems": 3,
                    "TotalPages": 1
                  },
                  "Filters": {
                    "Project": "akande",
                    "Category": null,
                    "Format": "svg",
                    "Query": null
                  },
                  "DateFetched": "2026-04-04T12:00:00.000Z",
                  "Data": [
                    {
                      "name": "logo.svg",
                      "path": "akande/v1/logos/logo.svg",
                      "project": "akande",
                      "category": "logos",
                      "format": "svg",
                      "size": 4523
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid AccessKey",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Asset manifest unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Asset manifest unavailable. Please try again later."
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -s -H 'AccessKey: YOUR_ACCESS_KEY' \\\n  'https://cloudcdn.pro/api/assets?project=akande&format=svg&page=1&per_page=50'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://cloudcdn.pro/api/assets?project=akande&format=svg', {\n  headers: { AccessKey: 'YOUR_ACCESS_KEY' }\n});\nconst data = await res.json();\nconsole.log(data.Data);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nres = requests.get(\n    'https://cloudcdn.pro/api/assets',\n    headers={'AccessKey': 'YOUR_ACCESS_KEY'},\n    params={'project': 'akande', 'format': 'svg'}\n)\nprint(res.json()['Data'])"
          }
        ]
      }
    },
    "/api/assets/metadata": {
      "get": {
        "operationId": "getAssetMetadata",
        "summary": "Get asset metadata",
        "description": "Returns detailed metadata for a single asset including available format variants, CDN URL, and transform URL.",
        "tags": [
          "Assets"
        ],
        "security": [
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "required": true,
            "description": "Full asset path from the manifest",
            "schema": {
              "type": "string"
            },
            "example": "akande/v1/logos/logo.svg"
          }
        ],
        "responses": {
          "200": {
            "description": "Asset metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetMetadata"
                },
                "example": {
                  "Path": "akande/v1/logos/logo.svg",
                  "Name": "logo.svg",
                  "Project": "akande",
                  "Category": "logos",
                  "Format": "svg",
                  "Size": 4523,
                  "SizeHuman": "4.4 KB",
                  "ContentType": "image/svg+xml",
                  "CdnUrl": "https://cloudcdn.pro/akande/v1/logos/logo.svg",
                  "TransformUrl": "https://cloudcdn.pro/api/transform?url=/akande/v1/logos/logo.svg",
                  "AvailableFormats": [
                    "svg",
                    "png",
                    "webp"
                  ],
                  "DateFetched": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Missing path parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Query parameter \"path\" is required"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Asset not found: nonexistent/path.svg"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Manifest unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Asset manifest unavailable. Please try again later."
                }
              }
            }
          }
        }
      }
    },
    "/api/storage/{path}": {
      "get": {
        "operationId": "storageGetOrList",
        "summary": "List directory or download file",
        "description": "If the path ends with `/` or has no file extension, lists directory contents in Bunny.net-compatible JSON. Otherwise, downloads the file. Auth: AccessKey header or dashboard session cookie.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "Storage path. Trailing slash = directory listing. File extension = download.",
            "schema": {
              "type": "string"
            },
            "example": "clients/akande/v1/logos/"
          }
        ],
        "responses": {
          "200": {
            "description": "Directory listing (JSON array) or file body (binary)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StorageFileEntry"
                  }
                },
                "example": [
                  {
                    "Guid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                    "StorageZoneName": "cloudcdn",
                    "Path": "/clients/akande/v1/logos/",
                    "ObjectName": "logo.svg",
                    "Length": 4523,
                    "LastChanged": "2026-04-04T12:00:00.000Z",
                    "ServerId": 0,
                    "ArrayNumber": 0,
                    "IsDirectory": false,
                    "UserId": "cloudcdn",
                    "ContentType": "",
                    "DateCreated": "2026-04-04T12:00:00.000Z",
                    "StorageZoneId": 0,
                    "Checksum": null,
                    "ReplicatedZones": ""
                  }
                ]
              },
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid path (e.g., path traversal attempt)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid path: path traversal not allowed"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "File not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "File not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Download failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Failed to download file from origin"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "storageUpload",
        "summary": "Upload file",
        "description": "Uploads a file to storage via GitHub API commit. Max file size: 25 MB. Supports optional SHA-256 checksum verification via the Checksum header. Triggers async cache purge on overwrites. Rate limit: none (auth-gated).",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "Destination file path",
            "schema": {
              "type": "string"
            },
            "example": "clients/akande/v1/logos/new-logo.svg"
          },
          {
            "name": "Checksum",
            "in": "header",
            "required": false,
            "description": "SHA-256 hex digest for integrity verification",
            "schema": {
              "type": "string"
            },
            "example": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Raw file bytes",
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "File uploaded successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadResponse"
                },
                "example": {
                  "HttpCode": 201,
                  "Message": "File uploaded successfully",
                  "Path": "akande/v1/logos/new-logo.svg",
                  "Length": 8192,
                  "Checksum": null,
                  "DateCreated": "2026-04-04T12:00:00.000Z",
                  "EdgeStatus": "pending",
                  "EdgeNote": "File committed to repository. It will be available at the edge after the CI/CD pipeline deploys (~60-90 seconds)."
                }
              }
            }
          },
          "400": {
            "description": "Invalid path or checksum mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Checksum mismatch: expected E3B0C4... got A1B2C3..."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "409": {
            "description": "Git conflict from concurrent upload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 409,
                  "Message": "Conflict: another upload modified the tree. Retry or use /api/storage/batch for concurrent uploads."
                }
              }
            }
          },
          "413": {
            "description": "Payload too large (max 25 MB)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "HttpCode": {
                      "type": "integer",
                      "example": 413
                    },
                    "Message": {
                      "type": "string"
                    },
                    "MaxSize": {
                      "type": "integer",
                      "example": 26214400
                    }
                  }
                },
                "example": {
                  "HttpCode": 413,
                  "Message": "Payload too large. Maximum file size is 25 MB.",
                  "MaxSize": 26214400
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "Upload backend not configured (GITHUB_TOKEN/GITHUB_REPO missing)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 501,
                  "Message": "Upload backend not configured"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X PUT \\\n  -H 'AccessKey: YOUR_ACCESS_KEY' \\\n  -H 'Content-Type: application/octet-stream' \\\n  --data-binary @logo.svg \\\n  'https://cloudcdn.pro/api/storage/clients/akande/v1/logos/new-logo.svg'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const file = await Deno.readFile('logo.svg'); // or fs.readFileSync\nconst res = await fetch('https://cloudcdn.pro/api/storage/clients/akande/v1/logos/new-logo.svg', {\n  method: 'PUT',\n  headers: { AccessKey: 'YOUR_ACCESS_KEY', 'Content-Type': 'application/octet-stream' },\n  body: file\n});\nconsole.log(await res.json());"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nwith open('logo.svg', 'rb') as f:\n    res = requests.put(\n        'https://cloudcdn.pro/api/storage/clients/akande/v1/logos/new-logo.svg',\n        headers={'AccessKey': 'YOUR_ACCESS_KEY', 'Content-Type': 'application/octet-stream'},\n        data=f.read()\n    )\nprint(res.json())"
          }
        ]
      },
      "delete": {
        "operationId": "storageDelete",
        "summary": "Delete file",
        "description": "Deletes a file from storage via GitHub API commit. Triggers async cache purge.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "File path to delete",
            "schema": {
              "type": "string"
            },
            "example": "clients/akande/v1/logos/old-logo.svg"
          }
        ],
        "responses": {
          "200": {
            "description": "File deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "File deleted successfully",
                  "Path": "akande/v1/logos/old-logo.svg",
                  "EdgeStatus": "purging",
                  "EdgeNote": "File removed from repository and edge cache purge initiated."
                }
              }
            }
          },
          "400": {
            "description": "Invalid path",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid path: path traversal not allowed"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "File not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "File not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "Delete backend not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 501,
                  "Message": "Delete backend not configured"
                }
              }
            }
          },
          "502": {
            "description": "GitHub API delete failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "GitHub API delete failed"
                }
              }
            }
          }
        }
      },
      "head": {
        "operationId": "storageHead",
        "summary": "File metadata (HEAD)",
        "description": "Returns Content-Length and Content-Type headers for a file without downloading the body.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "File path",
            "schema": {
              "type": "string"
            },
            "example": "clients/akande/v1/logos/logo.svg"
          }
        ],
        "responses": {
          "200": {
            "description": "File exists. Content-Length and Content-Type headers are set.",
            "headers": {
              "Content-Length": {
                "schema": {
                  "type": "string"
                },
                "description": "File size in bytes",
                "example": "4523"
              },
              "Content-Type": {
                "schema": {
                  "type": "string"
                },
                "description": "MIME type",
                "example": "image/svg+xml"
              }
            }
          },
          "400": {
            "description": "Invalid path"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "File not found"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/api/storage/batch": {
      "post": {
        "operationId": "storageBatchUpload",
        "summary": "Batch upload files",
        "description": "Uploads multiple files in a single Git commit using the GitHub Git Database API (Trees + Commits). Avoids 409 conflicts from concurrent Contents API calls. Max 50 files per batch, 25 MB per file.",
        "tags": [
          "Storage"
        ],
        "security": [
          {
            "AccessKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchUploadRequest"
              },
              "example": {
                "files": [
                  {
                    "path": "clients/akande/v1/logos/logo-dark.svg",
                    "content": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==",
                    "encoding": "base64"
                  },
                  {
                    "path": "clients/akande/v1/logos/logo-light.svg",
                    "content": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==",
                    "encoding": "base64"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Batch upload successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchUploadResponse"
                },
                "example": {
                  "HttpCode": 201,
                  "Message": "2 file(s) uploaded in a single commit",
                  "Commit": "abc123def456",
                  "Files": [
                    "clients/akande/v1/logos/logo-dark.svg",
                    "clients/akande/v1/logos/logo-light.svg"
                  ],
                  "EdgeStatus": "pending",
                  "EdgeNote": "Files committed. Available at the edge after CI/CD deploy (~60-90 seconds).",
                  "DateCreated": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Validation error (empty files array, missing fields, invalid path, exceeds 50 file limit)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Batch exceeds maximum of 50 files"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "413": {
            "description": "Individual file exceeds 25 MB limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 413,
                  "Message": "File 'clients/akande/v1/banners/hero.png' exceeds 25 MB limit"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "Upload backend not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 501,
                  "Message": "Upload backend not configured"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/core/zones": {
      "get": {
        "operationId": "listZones",
        "summary": "List all zones",
        "description": "Returns all tenant zones derived from the asset manifest. Each zone represents a client project with its file count, storage usage, and categories.",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of zones",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Zone"
                  }
                },
                "example": [
                  {
                    "Id": "akande",
                    "Name": "akande",
                    "StorageZoneName": "cloudcdn",
                    "OriginUrl": "https://cloudcdn.pro/akande/",
                    "FileCount": 45,
                    "StorageUsed": 2457600,
                    "StorageUsedHuman": "2.3 MB",
                    "Categories": [
                      "banners",
                      "icons",
                      "logos"
                    ],
                    "DateCreated": "2026-04-04T12:00:00.000Z",
                    "Enabled": true,
                    "Suspended": false
                  }
                ]
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized. Use AccountKey header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createZone",
        "summary": "Create a new zone",
        "description": "Creates a new tenant zone via Git commit. Scaffolds standard v1/ directories: banners, github, icons, logos, titles. Zone name must be 2-64 lowercase alphanumeric characters with hyphens.",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ZoneCreateRequest"
              },
              "example": {
                "Name": "newclient"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Zone created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZoneCreateResponse"
                },
                "example": {
                  "HttpCode": 201,
                  "Message": "Zone 'newclient' created successfully",
                  "Id": "newclient",
                  "Name": "newclient",
                  "OriginUrl": "https://cloudcdn.pro/newclient/",
                  "Commit": "abc123def456",
                  "Directories": [
                    "banners",
                    "github",
                    "icons",
                    "logos",
                    "titles"
                  ],
                  "EdgeStatus": "pending",
                  "EdgeNote": "Zone will be live after CI/CD deploy (~60-90 seconds).",
                  "DateCreated": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid zone name",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Name must be 2-64 alphanumeric characters with hyphens"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "409": {
            "description": "Zone already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 409,
                  "Message": "Zone 'newclient' already exists"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "GitHub backend not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 501,
                  "Message": "GitHub backend not configured"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST \\\n  -H 'AccountKey: YOUR_ACCOUNT_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"Name\": \"newclient\"}' \\\n  'https://cloudcdn.pro/api/core/zones'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://cloudcdn.pro/api/core/zones', {\n  method: 'POST',\n  headers: { AccountKey: 'YOUR_ACCOUNT_KEY', 'Content-Type': 'application/json' },\n  body: JSON.stringify({ Name: 'newclient' })\n});\nconsole.log(await res.json());"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nres = requests.post(\n    'https://cloudcdn.pro/api/core/zones',\n    headers={'AccountKey': 'YOUR_ACCOUNT_KEY'},\n    json={'Name': 'newclient'}\n)\nprint(res.json())"
          }
        ]
      }
    },
    "/api/core/zones/{id}": {
      "get": {
        "operationId": "getZone",
        "summary": "Get zone details",
        "description": "Returns detailed information about a zone including all files, categories, formats, and storage usage.",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Zone identifier (project name)",
            "schema": {
              "type": "string"
            },
            "example": "akande"
          }
        ],
        "responses": {
          "200": {
            "description": "Zone detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZoneDetail"
                },
                "example": {
                  "Id": "akande",
                  "Name": "akande",
                  "StorageZoneName": "cloudcdn",
                  "OriginUrl": "https://cloudcdn.pro/akande/",
                  "FileCount": 45,
                  "StorageUsed": 2457600,
                  "StorageUsedHuman": "2.3 MB",
                  "Categories": [
                    "banners",
                    "icons",
                    "logos"
                  ],
                  "Formats": [
                    "png",
                    "svg",
                    "webp"
                  ],
                  "Files": [
                    {
                      "Path": "akande/v1/logos/logo.svg",
                      "Name": "logo.svg",
                      "Format": "svg",
                      "Size": 4523,
                      "Category": "logos"
                    },
                    {
                      "Path": "akande/v1/banners/hero.webp",
                      "Name": "hero.webp",
                      "Format": "webp",
                      "Size": 142000,
                      "Category": "banners"
                    }
                  ],
                  "Enabled": true,
                  "Suspended": false,
                  "DateCreated": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Zone ID required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Zone ID is required"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Zone not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Zone 'unknown' not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteZone",
        "summary": "Delete zone",
        "description": "Deletes an entire zone and all its files via a single Git commit. Triggers async cache purge by project tag.",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Zone identifier to delete",
            "schema": {
              "type": "string"
            },
            "example": "oldclient"
          }
        ],
        "responses": {
          "200": {
            "description": "Zone deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZoneDeleteResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Zone 'oldclient' deleted (12 files removed)",
                  "Commit": "abc123def456",
                  "FilesRemoved": 12,
                  "EdgeStatus": "purging"
                }
              }
            }
          },
          "400": {
            "description": "Invalid zone ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid zone ID"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Zone not found or already empty",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Zone 'oldclient' not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "GitHub backend not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 501,
                  "Message": "GitHub backend not configured"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/core/zones/{id}/domains": {
      "post": {
        "operationId": "addDomain",
        "summary": "Add custom domain to zone",
        "description": "Adds a custom domain to a zone via the Cloudflare Pages API. SSL certificate is provisioned automatically. Requires CNAME pointed to cloudcdn-pro.pages.dev.",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Zone identifier",
            "schema": {
              "type": "string"
            },
            "example": "akande"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DomainAddRequest"
              },
              "example": {
                "Hostname": "cdn.akande.com"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Domain added, SSL provisioning",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DomainAddResponse"
                },
                "example": {
                  "HttpCode": 201,
                  "Message": "Custom domain 'cdn.akande.com' added successfully",
                  "Zone": "akande",
                  "Hostname": "cdn.akande.com",
                  "SslStatus": "provisioning",
                  "Note": "SSL certificate will be provisioned automatically. Point your CNAME to cloudcdn-pro.pages.dev.",
                  "DateCreated": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid hostname or Cloudflare rejection",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid hostname format"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "Cloudflare credentials not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 501,
                  "Message": "Cloudflare credentials not configured"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/core/statistics": {
      "get": {
        "operationId": "getStatistics",
        "summary": "Get edge statistics",
        "description": "Returns bandwidth, requests, cache ratios, geographic distribution, and top assets from the analytics KV store. Optionally filtered by zone. Data retained for up to 90 days.",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "description": "Number of days to look back (1-90)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 7
            },
            "example": 7
          },
          {
            "name": "zone",
            "in": "query",
            "description": "Filter statistics to a specific zone",
            "schema": {
              "type": "string"
            },
            "example": "akande"
          }
        ],
        "responses": {
          "200": {
            "description": "Edge statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatisticsResponse"
                },
                "example": {
                  "Period": {
                    "Days": 7,
                    "Zone": "all"
                  },
                  "Summary": {
                    "TotalRequests": 125000,
                    "TotalBandwidth": 5368709120,
                    "TotalBandwidthHuman": "5.00 GB",
                    "CacheHitRate": "94.2%",
                    "UniqueCountries": 42
                  },
                  "Daily": [
                    {
                      "Date": "2026-04-03",
                      "TotalRequests": 18000,
                      "Bandwidth": 768000000,
                      "BandwidthHuman": "732.4 MB",
                      "CacheHit": 17000,
                      "CacheMiss": 1000
                    }
                  ],
                  "TopAssets": [
                    {
                      "Path": "/akande/v1/logos/logo.svg",
                      "Requests": 5400
                    }
                  ],
                  "GeoDistribution": [
                    {
                      "CountryCode": "US",
                      "Requests": 45000
                    },
                    {
                      "CountryCode": "DE",
                      "Requests": 12000
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Analytics store unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Analytics store unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/core/rules": {
      "get": {
        "operationId": "getRules",
        "summary": "Read edge rules",
        "description": "Returns the current contents of _headers and _redirects edge rule files.",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Current edge rules",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RulesResponse"
                },
                "example": {
                  "Headers": "/*.webp\n  Cache-Control: public, max-age=31536000, immutable",
                  "Redirects": "/old-path /new-path 301",
                  "Editable": [
                    "_headers",
                    "_redirects"
                  ],
                  "DateFetched": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "updateRules",
        "summary": "Update edge rules",
        "description": "Updates _headers or _redirects via a Git commit. Content max size: 100 KB. Changes take effect after CI/CD deploy (~60-90 seconds).",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RulesUpdateRequest"
              },
              "example": {
                "File": "_headers",
                "Content": "/*.webp\n  Cache-Control: public, max-age=31536000, immutable\n  Content-Type: image/webp"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rules updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RulesUpdateResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "_headers updated successfully",
                  "File": "_headers",
                  "Commit": "abc123def456",
                  "EdgeStatus": "pending",
                  "EdgeNote": "Edge rules will take effect after CI/CD deploy (~60-90 seconds).",
                  "DateModified": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid file name or content",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "File must be _headers or _redirects"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "GitHub backend not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 501,
                  "Message": "GitHub backend not configured"
                }
              }
            }
          },
          "502": {
            "description": "GitHub API update failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "GitHub API update failed"
                }
              }
            }
          }
        }
      }
    },
    "/api/insights/summary": {
      "get": {
        "operationId": "getInsightsSummary",
        "summary": "Analytics summary",
        "description": "Aggregate analytics summary: total requests, bandwidth, cache hit rate, and unique countries. Accepts either AccountKey or AccessKey for authentication.",
        "tags": [
          "Insights"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "description": "Number of days to look back (1-90)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 7
            },
            "example": 7
          },
          {
            "name": "zone",
            "in": "query",
            "description": "Filter to a specific zone",
            "schema": {
              "type": "string"
            },
            "example": "akande"
          }
        ],
        "responses": {
          "200": {
            "description": "Summary statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InsightsSummaryResponse"
                },
                "example": {
                  "Period": {
                    "Days": 7,
                    "Zone": "all"
                  },
                  "TotalRequests": 125000,
                  "TotalBandwidth": "5.00 GB",
                  "TotalBandwidthBytes": 5368709120,
                  "CacheHitRate": "94.2%",
                  "UniqueCountries": 42,
                  "DateFetched": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Analytics unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Analytics store unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/insights/top-assets": {
      "get": {
        "operationId": "getTopAssets",
        "summary": "Top requested assets",
        "description": "Returns the most-requested assets over the specified period, ranked by request count. Accepts either AccountKey or AccessKey.",
        "tags": [
          "Insights"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "description": "Number of days to look back (1-90)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 7
            },
            "example": 7
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of assets to return (1-100)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "example": 20
          }
        ],
        "responses": {
          "200": {
            "description": "Top assets list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TopAssetsResponse"
                },
                "example": {
                  "Period": {
                    "Days": 7
                  },
                  "Assets": [
                    {
                      "Path": "/akande/v1/logos/logo.svg",
                      "Requests": 5400
                    },
                    {
                      "Path": "/bankingonai/v1/banners/hero.webp",
                      "Requests": 3200
                    }
                  ],
                  "DateFetched": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Analytics unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Analytics store unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/insights/geography": {
      "get": {
        "operationId": "getGeography",
        "summary": "Geographic distribution",
        "description": "Returns request counts by country (ISO 3166-1 alpha-2 codes), sorted descending by volume. Accepts either AccountKey or AccessKey.",
        "tags": [
          "Insights"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "description": "Number of days to look back (1-90)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 7
            },
            "example": 7
          }
        ],
        "responses": {
          "200": {
            "description": "Geographic distribution",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeographyResponse"
                },
                "example": {
                  "Period": {
                    "Days": 7
                  },
                  "Countries": [
                    {
                      "CountryCode": "US",
                      "Requests": 45000
                    },
                    {
                      "CountryCode": "DE",
                      "Requests": 12000
                    },
                    {
                      "CountryCode": "JP",
                      "Requests": 8500
                    }
                  ],
                  "DateFetched": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Analytics unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Analytics store unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/insights/errors": {
      "get": {
        "operationId": "getErrors",
        "summary": "Error tracking",
        "description": "Returns 4xx/5xx error counts grouped by status code with the top 10 paths per code. Error data populates automatically from middleware analytics. Accepts either AccountKey or AccessKey.",
        "tags": [
          "Insights"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "description": "Number of days to look back (1-90)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 7
            },
            "example": 7
          }
        ],
        "responses": {
          "200": {
            "description": "Error tracking data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorsResponse"
                },
                "example": {
                  "Period": {
                    "Days": 7
                  },
                  "Errors": [
                    {
                      "StatusCode": 404,
                      "Count": 230,
                      "TopPaths": [
                        {
                          "Path": "/missing/asset.png",
                          "Count": 50
                        },
                        {
                          "Path": "/old/removed-file.webp",
                          "Count": 30
                        }
                      ]
                    }
                  ],
                  "DateFetched": "2026-04-04T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Analytics unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Analytics store unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/transform": {
      "get": {
        "operationId": "transformImage",
        "summary": "Transform image",
        "description": "On-the-fly image transformation via Cloudflare Image Resizing. Supports resize, crop, format conversion, blur, and sharpen. Public endpoint (no auth required). Rate limit: 50,000 transforms per calendar month. Responses are cached for 1 year with immutable directive.",
        "tags": [
          "Delivery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Source image URL. Absolute URL or path relative to the CDN origin.",
            "schema": {
              "type": "string"
            },
            "example": "/akande/v1/banners/hero.webp"
          },
          {
            "name": "w",
            "in": "query",
            "description": "Output width in pixels (1-8192)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 8192
            },
            "example": 800
          },
          {
            "name": "h",
            "in": "query",
            "description": "Output height in pixels (1-8192)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 8192
            },
            "example": 600
          },
          {
            "name": "fit",
            "in": "query",
            "description": "Resize fit mode",
            "schema": {
              "type": "string",
              "enum": [
                "cover",
                "contain",
                "fill",
                "inside",
                "outside"
              ]
            },
            "example": "cover"
          },
          {
            "name": "format",
            "in": "query",
            "description": "Output format. 'auto' negotiates via Accept header.",
            "schema": {
              "type": "string",
              "enum": [
                "auto",
                "webp",
                "avif",
                "png",
                "jpeg"
              ]
            },
            "example": "webp"
          },
          {
            "name": "q",
            "in": "query",
            "description": "Output quality (1-100)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "example": 85
          },
          {
            "name": "blur",
            "in": "query",
            "description": "Blur radius (1-250)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250
            },
            "example": 10
          },
          {
            "name": "sharpen",
            "in": "query",
            "description": "Sharpen amount (1-10)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10
            },
            "example": 2
          },
          {
            "name": "gravity",
            "in": "query",
            "description": "Crop gravity / focus point",
            "schema": {
              "type": "string",
              "enum": [
                "center",
                "north",
                "south",
                "east",
                "west",
                "northeast",
                "northwest",
                "southeast",
                "southwest",
                "face",
                "auto"
              ]
            },
            "example": "center"
          }
        ],
        "responses": {
          "200": {
            "description": "Transformed image binary. Content-Type matches the output format.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, max-age=31536000, immutable"
              },
              "Vary": {
                "schema": {
                  "type": "string"
                },
                "description": "Accept"
              }
            },
            "content": {
              "image/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameter or missing url",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Invalid parameter: w must be 1-8192"
                }
              }
            }
          },
          "429": {
            "description": "Monthly transform limit reached (50,000/month)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "limit_reached"
                    },
                    "message": {
                      "type": "string",
                      "example": "Monthly transform limit reached."
                    }
                  }
                },
                "example": {
                  "error": "limit_reached",
                  "message": "Monthly transform limit reached."
                }
              }
            }
          },
          "500": {
            "description": "Transform failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Transform failed: internal error"
                }
              }
            }
          },
          "502": {
            "description": "Upstream returned an error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Upstream returned 404 for the source image"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -s -o transformed.webp \\\n  'https://cloudcdn.pro/api/transform?url=/akande/v1/banners/hero.webp&w=800&h=600&fit=cover&format=webp&q=85'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch(\n  'https://cloudcdn.pro/api/transform?url=/akande/v1/banners/hero.webp&w=800&h=600&fit=cover&format=webp&q=85'\n);\nconst blob = await res.blob();\nconsole.log(`Transformed: ${blob.size} bytes, ${blob.type}`);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nres = requests.get(\n    'https://cloudcdn.pro/api/transform',\n    params={'url': '/akande/v1/banners/hero.webp', 'w': 800, 'h': 600, 'fit': 'cover', 'format': 'webp', 'q': 85}\n)\nwith open('transformed.webp', 'wb') as f:\n    f.write(res.content)\nprint(f'Saved {len(res.content)} bytes')"
          }
        ]
      }
    },
    "/api/auto": {
      "get": {
        "operationId": "autoFormat",
        "summary": "Automatic format negotiation",
        "description": "Serves the best image format based on the client's Accept header. Still-image fallback chain (preference order): JXL -> AVIF -> HEIF/HEIC -> WebP -> PNG -> SVG. Animated variant available via `?anim=1`: animated AVIF (.avifs) -> animated WebP -> APNG -> GIF. JXL/AVIF/HEIF/HEIC and animated formats require explicit Accept opt-in; WebP, PNG, SVG, and GIF are universal fallbacks. Public endpoint (no auth). Also supports path-based routing: `/api/auto/{path}`. Responses cached for 1 year with Vary: Accept, Save-Data, Sec-CH-Effective-Connection-Type.",
        "tags": [
          "Delivery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "required": true,
            "description": "Asset path without file extension (e.g., /akande/v1/logos/logo)",
            "schema": {
              "type": "string"
            },
            "example": "/akande/v1/logos/logo"
          },
          {
            "name": "anim",
            "in": "query",
            "required": false,
            "description": "When set to `1`, negotiate from the animated chain (.avifs, animated .webp, .apng, .gif) instead of the still chain.",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ]
            },
            "example": "1"
          }
        ],
        "responses": {
          "200": {
            "description": "Image in the best supported format. Content-Type header indicates the negotiated format (image/jxl, image/avif, image/avif-sequence, image/heic, image/heif, image/webp, image/png, image/apng, image/gif, image/svg+xml).",
            "headers": {
              "Vary": {
                "schema": {
                  "type": "string"
                },
                "description": "Accept, Save-Data, Sec-CH-Effective-Connection-Type"
              },
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, max-age=31536000, immutable"
              },
              "Content-Type": {
                "schema": {
                  "type": "string"
                },
                "description": "Negotiated MIME type — one of image/jxl, image/avif, image/avif-sequence, image/heic, image/heif, image/webp, image/png, image/apng, image/gif, image/svg+xml."
              }
            },
            "content": {
              "image/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Missing path parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Missing required parameter: path"
                }
              }
            }
          },
          "404": {
            "description": "No suitable format found for the given path",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "No suitable format found for the given path"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auto/{path}": {
      "get": {
        "operationId": "autoFormatPath",
        "summary": "Path-based automatic format negotiation",
        "description": "Catch-all route for path-based format negotiation. Delegates to the main auto handler by rewriting the URL path segments into a query parameter. Serves the best image format based on the client's Accept header. Fallback chain: avif -> webp -> png -> svg. Public endpoint (no auth). Responses cached for 1 year with Vary: Accept.",
        "tags": [
          "Delivery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "Asset path without file extension (e.g., bankingonai/images/logos/logo). Supports multiple path segments via catch-all routing.",
            "schema": {
              "type": "string"
            },
            "example": "bankingonai/images/logos/logo"
          }
        ],
        "responses": {
          "200": {
            "description": "Image in the best supported format. Content-Type header indicates the negotiated format.",
            "headers": {
              "Vary": {
                "schema": {
                  "type": "string"
                },
                "description": "Accept"
              },
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, max-age=31536000, immutable"
              },
              "Content-Type": {
                "schema": {
                  "type": "string"
                },
                "description": "Negotiated MIME type (image/avif, image/webp, image/png, or image/svg+xml)"
              }
            },
            "content": {
              "image/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Missing path parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Missing required parameter: path"
                }
              }
            }
          },
          "404": {
            "description": "No suitable format found for the given path",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "No suitable format found for the given path"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/api/signed": {
      "get": {
        "operationId": "verifySignedUrl",
        "summary": "Verify signed URL",
        "description": "Validates an HMAC-SHA256 signed URL, checks expiration, and proxies the protected asset from origin. Uses constant-time comparison to prevent timing attacks. Responses cached privately for 1 hour. Public endpoint (signature is the auth).",
        "tags": [
          "Delivery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "required": true,
            "description": "Protected asset path",
            "schema": {
              "type": "string"
            },
            "example": "/protected/client-report.pdf"
          },
          {
            "name": "expires",
            "in": "query",
            "required": true,
            "description": "Expiration timestamp (Unix seconds)",
            "schema": {
              "type": "integer"
            },
            "example": 1712248800
          },
          {
            "name": "sig",
            "in": "query",
            "required": true,
            "description": "HMAC-SHA256 hex signature of \"{path}:{expires}\"",
            "schema": {
              "type": "string"
            },
            "example": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
          }
        ],
        "responses": {
          "200": {
            "description": "Protected asset content",
            "headers": {
              "X-Signed-URL": {
                "schema": {
                  "type": "string"
                },
                "description": "Set to 'verified' on successful validation"
              },
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "private, max-age=3600"
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "403": {
            "description": "Missing parameters, expired URL, or invalid signature",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "URL expired"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Server misconfigured (SIGNED_URL_SECRET not set)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Server misconfigured: SIGNED_URL_SECRET not set"
                }
              }
            }
          },
          "502": {
            "description": "Failed to fetch asset from origin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Failed to fetch asset from origin"
                }
              }
            }
          }
        }
      }
    },
    "/api/stream": {
      "get": {
        "operationId": "streamVideo",
        "summary": "HLS video streaming",
        "description": "Pseudo-HLS streaming endpoint. Without quality parameter, returns a master M3U8 playlist. With quality, returns a variant playlist. With quality and segment, returns a byte-range video segment. Public endpoint (no auth). Available videos: black, mount_fuji, nature. Available qualities: 1080, 720, 480. Segment duration: 10 seconds. Segments cached for 1 year.",
        "tags": [
          "Delivery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "video",
            "in": "query",
            "required": true,
            "description": "Video name",
            "schema": {
              "type": "string",
              "enum": [
                "black",
                "mount_fuji",
                "nature"
              ]
            },
            "example": "nature"
          },
          {
            "name": "quality",
            "in": "query",
            "description": "Stream quality. Omit for master playlist.",
            "schema": {
              "type": "string",
              "enum": [
                "1080",
                "720",
                "480"
              ]
            },
            "example": "720"
          },
          {
            "name": "segment",
            "in": "query",
            "description": "Segment index (0-based). Requires quality parameter.",
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "M3U8 playlist or video segment",
            "content": {
              "application/vnd.apple.mpegurl": {
                "schema": {
                  "type": "string"
                },
                "example": "#EXTM3U\n#EXT-X-VERSION:3\n\n#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720,NAME=\"720p\"\n/api/stream?video=nature&quality=720"
              },
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid video, quality, or segment parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Invalid video. Available: black, mount_fuji, nature"
                }
              }
            }
          },
          "404": {
            "description": "Video not found or segment out of range",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Segment out of range"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Failed to fetch segment from origin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Failed to fetch segment from origin"
                }
              }
            }
          }
        }
      }
    },
    "/api/purge": {
      "post": {
        "operationId": "purgeCache",
        "summary": "Purge CDN cache",
        "description": "Invalidates cached content via the Cloudflare API. Supports three modes (exactly one per request): specific URLs (max 30), cache tags (max 30), or purge everything. Rate limit: 100 purge requests per day. Auth: x-api-key header (PURGE_KEY).",
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "PurgeKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PurgeRequest"
              },
              "examples": {
                "byUrls": {
                  "summary": "Purge specific URLs",
                  "value": {
                    "urls": [
                      "https://cloudcdn.pro/akande/v1/logos/logo.svg",
                      "https://cloudcdn.pro/akande/v1/logos/logo.webp"
                    ]
                  }
                },
                "byTags": {
                  "summary": "Purge by cache tags",
                  "value": {
                    "tags": [
                      "project-akande",
                      "type-banner"
                    ]
                  }
                },
                "everything": {
                  "summary": "Purge entire cache",
                  "value": {
                    "purge_everything": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Purge successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PurgeResponse"
                },
                "example": {
                  "success": true,
                  "purged": [
                    "https://cloudcdn.pro/akande/v1/logos/logo.svg"
                  ],
                  "remaining_today": 95,
                  "cloudflare": {
                    "success": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error (empty arrays, too many URLs/tags, invalid URL prefix, multiple modes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "All URLs must start with https://cloudcdn.pro/",
                  "invalid": [
                    "https://evil.com/payload"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized (missing or invalid x-api-key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Unauthorized: invalid or missing x-api-key"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (max 100 purges per day)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Rate limit exceeded: max 100 purges per day"
                }
              }
            }
          },
          "500": {
            "description": "Server misconfigured (missing Cloudflare credentials)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Server misconfigured: missing Cloudflare credentials"
                }
              }
            }
          },
          "502": {
            "description": "Cloudflare API call failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Cloudflare API call failed"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST \\\n  -H 'x-api-key: YOUR_PURGE_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"urls\": [\"https://cloudcdn.pro/akande/v1/logos/logo.svg\"]}' \\\n  'https://cloudcdn.pro/api/purge'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://cloudcdn.pro/api/purge', {\n  method: 'POST',\n  headers: { 'x-api-key': 'YOUR_PURGE_KEY', 'Content-Type': 'application/json' },\n  body: JSON.stringify({ urls: ['https://cloudcdn.pro/akande/v1/logos/logo.svg'] })\n});\nconsole.log(await res.json());"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nres = requests.post(\n    'https://cloudcdn.pro/api/purge',\n    headers={'x-api-key': 'YOUR_PURGE_KEY'},\n    json={'urls': ['https://cloudcdn.pro/akande/v1/logos/logo.svg']}\n)\nprint(res.json())"
          }
        ]
      }
    },
    "/api/analytics": {
      "get": {
        "operationId": "getAnalytics",
        "summary": "Get analytics report",
        "description": "Returns daily analytics data including hits, bandwidth, top assets, geographic distribution, and cache ratios. Auth: x-api-key header (ANALYTICS_KEY). Data retained for 35 days in KV.",
        "tags": [
          "Insights"
        ],
        "security": [
          {
            "AnalyticsKey": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "description": "Number of days to look back (1-30)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30,
              "default": 7
            },
            "example": 7
          }
        ],
        "responses": {
          "200": {
            "description": "Daily analytics data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsReportResponse"
                },
                "example": {
                  "days": 7,
                  "data": [
                    {
                      "date": "2026-04-03",
                      "hits": 18000,
                      "bandwidth": {
                        "bytes": 768000000,
                        "human": "732.42 MB"
                      },
                      "top_assets": {
                        "/akande/v1/logos/logo.svg": 1200
                      },
                      "geo": {
                        "US": 8000,
                        "DE": 3000
                      },
                      "cache": {
                        "hit": 17000,
                        "miss": 1000,
                        "ratio": "94.4%"
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Unauthorized: invalid or missing x-api-key"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "trackAnalytics",
        "summary": "Record analytics hit",
        "description": "Programmatic endpoint for recording a request hit. Called by the trackRequest middleware helper. Increments daily counters for hits, bandwidth, top assets, geo, and cache status. Public endpoint (no auth) -- intended for internal use by edge middleware.",
        "tags": [
          "Insights"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnalyticsTrackRequest"
              },
              "example": {
                "path": "/akande/v1/logos/logo.svg",
                "bytes": 4523,
                "country": "US",
                "cache": "HIT"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hit recorded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Invalid JSON body"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/search": {
      "get": {
        "operationId": "searchAssets",
        "summary": "Semantic asset search",
        "description": "Searches assets using vector similarity (Vectorize + Workers AI embeddings) with automatic fallback to token-scored fuzzy matching against the manifest. Public endpoint (no auth). Results cached for 60 seconds. Vector search threshold: score > 0.5.",
        "tags": [
          "AI"
        ],
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search query (natural language or keywords)",
            "schema": {
              "type": "string"
            },
            "example": "dark blue banking background"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum results to return (1-50)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            },
            "example": 20
          }
        ],
        "responses": {
          "200": {
            "description": "Search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                },
                "example": {
                  "results": [
                    {
                      "name": "hero-dark.webp",
                      "path": "bankingonai/v1/banners/hero-dark.webp",
                      "project": "bankingonai",
                      "category": "banners",
                      "format": "webp",
                      "size": 142000,
                      "score": 0.847
                    }
                  ],
                  "query": "dark blue banking background",
                  "count": 1
                }
              }
            }
          },
          "400": {
            "description": "Missing query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Query parameter \"q\" is required"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Search failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Search failed: internal error"
                }
              }
            }
          }
        }
      }
    },
    "/api/chat": {
      "post": {
        "operationId": "chatConcierge",
        "summary": "AI Chat Concierge",
        "description": "RAG-powered conversational AI assistant for CloudCDN. Uses Workers AI (Llama 3.1 8B) with Vectorize for context retrieval. Returns a Server-Sent Events (SSE) stream with metadata, token, done, and error events. Rate limits: 1,000 queries/month, 100 queries/day (soft). Public endpoint (no auth). Last 5 conversation history turns are used for context.",
        "tags": [
          "AI"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatRequest"
              },
              "example": {
                "message": "What image formats does CloudCDN support?",
                "history": [
                  {
                    "role": "user",
                    "content": "Tell me about pricing"
                  },
                  {
                    "role": "assistant",
                    "content": "We have 3 tiers: Free ($0), Pro ($29/mo), and Enterprise (custom)."
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSE stream with metadata, token, done, and error events",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Server-Sent Events stream. Event types:\n- `metadata`: `{sources: string[], confidence: 'high'|'medium'|'low', remaining: number|null}`\n- `token`: `{text: string}` (individual response tokens)\n- `done`: `{followUps: string[]}` (2-3 suggested follow-up questions)\n- `error`: `{error: string}`"
                },
                "example": "event: metadata\ndata: {\"sources\":[\"api-reference\"],\"confidence\":\"high\",\"remaining\":950}\n\nevent: token\ndata: {\"text\":\"CloudCDN\"}\n\nevent: token\ndata: {\"text\":\" supports\"}\n\nevent: done\ndata: {\"followUps\":[\"How do I convert formats?\",\"What about video?\"]}\n"
              }
            },
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "no-cache, no-store"
              },
              "Connection": {
                "schema": {
                  "type": "string"
                },
                "description": "keep-alive"
              }
            }
          },
          "400": {
            "description": "Invalid JSON body or missing message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Message is required"
                }
              }
            }
          },
          "429": {
            "description": "Monthly query limit reached (1,000/month)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "limit_reached"
                    },
                    "message": {
                      "type": "string",
                      "example": "Monthly query limit reached. The Concierge will be back next month."
                    }
                  }
                },
                "example": {
                  "error": "limit_reached",
                  "message": "Monthly query limit reached. The Concierge will be back next month."
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonErrorResponse"
                },
                "example": {
                  "error": "Internal error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/ai/alt-text": {
      "get": {
        "operationId": "altTextGet",
        "summary": "Generate alt text (GET)",
        "description": "Generate accessibility-quality alt text for an image using a Workers AI vision model (LLaVA). Result is cached for 24 hours per asset path; repeated requests cost zero neurons. When the daily Workers AI neuron budget is exhausted the endpoint returns 503 rather than a hallucinated answer.",
        "tags": [
          "AI"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Relative asset path (e.g. `/clients/akande/v1/logos/logo.svg`). Absolute URLs are rejected.",
            "schema": {
              "type": "string",
              "maxLength": 2048
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Alt text generated or replayed from cache",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AltTextResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Asset unreachable or exceeds vision-model size cap",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (60 req/min/IP)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Vision model returned no usable text",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream returned empty response"
                }
              }
            }
          },
          "503": {
            "description": "AI binding missing or daily neuron budget exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Service temporarily unavailable"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "altTextPost",
        "summary": "Generate alt text (POST)",
        "description": "Same as GET but accepts the asset URL in a JSON body — useful for clients that prefer POST semantics for AI calls.",
        "tags": [
          "AI"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "Relative asset path."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Alt text generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AltTextResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Invalid body or URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Asset unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Empty AI response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream returned empty response"
                }
              }
            }
          },
          "503": {
            "description": "AI unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Service temporarily unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/ai/smart-crop": {
      "get": {
        "operationId": "smartCropGet",
        "summary": "AI smart-crop gravity (GET)",
        "description": "Identify the subject of an image and return a `gravity` value compatible with `/api/transform?gravity=`. Output is one of nine compass directions plus `face` and `center`, with a confidence band (`high|medium|low`). Cached 24 hours per asset path. Chain with the transform endpoint to produce subject-aware thumbnails.",
        "tags": [
          "AI"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 2048
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Smart-crop gravity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmartCropResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Asset unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "AI unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Service temporarily unavailable"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "smartCropPost",
        "summary": "AI smart-crop gravity (POST)",
        "description": "Same as GET but accepts the asset URL in a JSON body.",
        "tags": [
          "AI"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Smart-crop gravity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SmartCropResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Bad input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Asset unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway - AI model returned no usable response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Smart-crop model returned no usable gravity"
                }
              }
            }
          },
          "503": {
            "description": "AI unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Service temporarily unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/ai/moderate": {
      "get": {
        "operationId": "moderateGet",
        "summary": "AI image moderation (GET)",
        "description": "Classify an image across five safety categories (nudity, violence, drugs, hate symbols, gore) using a Workers AI vision model. Returns a verdict (`safe`|`borderline`|`unsafe`) plus per-category 0-1 scores. On unparseable model output the endpoint conservatively returns `borderline` so automated gates still have to decide. Cached 24 hours per asset.",
        "tags": [
          "AI"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 2048
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Moderation verdict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModerationResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Asset unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "AI unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Service temporarily unavailable"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "moderatePost",
        "summary": "AI image moderation (POST)",
        "description": "Same as GET but accepts the asset URL in a JSON body.",
        "tags": [
          "AI"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Moderation verdict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModerationResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Bad input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "Asset unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway - AI model returned no usable response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Moderation model returned no usable verdict"
                }
              }
            }
          },
          "503": {
            "description": "AI unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Service temporarily unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/lqip": {
      "get": {
        "operationId": "lqip",
        "summary": "Low-quality image placeholder",
        "description": "Generate a base64 data URI for a tiny blurred WebP placeholder. Use as `<img src>` or CSS `background-image` while the full asset loads. Result is deterministic per (url, size, blur) and cached for 24 hours. No Workers AI cost — uses Cloudflare Image Resizing directly.",
        "tags": [
          "Delivery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 2048
            },
            "description": "Relative asset path."
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 8,
              "maximum": 64,
              "default": 32
            },
            "description": "Placeholder width in pixels."
          },
          {
            "name": "blur",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 30
            },
            "description": "Gaussian blur radius."
          }
        ],
        "responses": {
          "200": {
            "description": "Placeholder data URI",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LqipResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "404": {
            "description": "Origin asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited (200/min/IP)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Origin unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream returned empty response"
                }
              }
            }
          }
        }
      }
    },
    "/api/blurhash": {
      "get": {
        "operationId": "blurhash",
        "summary": "Content-addressable placeholder hash",
        "description": "Companion to `/api/lqip` returning both a 40-char SHA-256 content hash and a base64 data URI. Use the hash to dedupe placeholder caches by content. Same source pipeline as LQIP; cached 24 h per (url, size).",
        "tags": [
          "Delivery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 2048
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 8,
              "maximum": 64,
              "default": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Placeholder hash + data URI",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlurhashResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "404": {
            "description": "Origin asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 404,
                  "Message": "Not found"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Origin unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream returned empty response"
                }
              }
            }
          }
        }
      }
    },
    "/api/insights/asset": {
      "get": {
        "operationId": "insightsAsset",
        "summary": "Per-asset analytics",
        "description": "Return daily request counts and error roll-ups for a single asset path. Useful for dashboards that need 'how is THIS asset performing' — rolled-up totals come from the existing `/api/insights/summary`. Path matching tolerates leading-slash differences.",
        "tags": [
          "Insights"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 2048
            },
            "description": "Asset path to query."
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 7
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-asset analytics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetInsightsResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid path",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Analytics KV unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Service temporarily unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/core/audit-logs": {
      "get": {
        "operationId": "auditLogs",
        "summary": "Audit log reader",
        "description": "Read the persistent control-plane audit trail. Each entry carries timestamp, action, client IP, user agent, request trace ID, and action-specific metadata. AccountKey-gated. 90-day retention.",
        "tags": [
          "Core"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 7
            }
          },
          {
            "name": "action",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter to one action (`token.create`, `token.revoke`, `webhook.create`, `webhook.delete`, `zone.create`, `purge.execute`)."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5000,
              "default": 500
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audit log entries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditLogResponse"
                },
                "example": {
                  "HttpCode": 200,
                  "Message": "Error"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - invalid filters (days/action/limit).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid query parameter"
                }
              }
            }
          },
          "401": {
            "description": "AccountKey required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited - too many requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Audit KV unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 503,
                  "Message": "Service temporarily unavailable"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Service health and binding status",
        "description": "Health probe for monitors and operators. By default returns a cheap binding-presence summary (no I/O). Pass `?deep=1` to actually exercise each binding: ASSETS via a manifest.json fetch, RATE_KV via a probe key read, plus shape checks for AI, VECTOR_INDEX, RATE_LIMITER, METRICS, WEBHOOK_QUEUE, and AUDIT_LOG_KV.\n\nHTTP status reflects health: 200 when ok, 503 when degraded. Required bindings (ASSETS, RATE_KV) degrade the service when missing or broken; optional bindings only degrade when configured-but-broken (so a deploy that hasn't enabled the AI surface stays 200 ok).\n\nPublic endpoint (no auth). Cache: no-store.",
        "tags": [
          "AI"
        ],
        "security": [],
        "parameters": [
          {
            "name": "deep",
            "in": "query",
            "required": false,
            "description": "When set to `1`, run real I/O probes against ASSETS and RATE_KV. Adds 1-2 round-trips per check; safe for low-frequency monitoring.",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ]
            },
            "example": "1"
          }
        ],
        "responses": {
          "200": {
            "description": "Service is healthy. All required bindings reachable; any configured optional bindings also reachable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "example": {
                  "status": "ok",
                  "timestamp": "2026-05-13T20:00:00.000Z",
                  "apiVersion": "2026-04-01",
                  "bindings": {
                    "assets": true,
                    "kv": true,
                    "ai": true,
                    "vectorize": true,
                    "rateLimiter": false,
                    "metrics": false,
                    "webhookQueue": false,
                    "auditLogKv": true
                  },
                  "checks": [
                    {
                      "name": "assets",
                      "configured": true,
                      "healthy": true,
                      "latencyMs": 8,
                      "method": "manifest-fetch"
                    },
                    {
                      "name": "kv",
                      "configured": true,
                      "healthy": true,
                      "latencyMs": 3,
                      "method": "kv-get"
                    },
                    {
                      "name": "ai",
                      "configured": true,
                      "healthy": true,
                      "method": "shape",
                      "optional": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "Service is degraded. At least one required binding is missing or unreachable, or a configured optional binding is broken. Inspect the `checks` array to identify which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "example": {
                  "status": "degraded",
                  "timestamp": "2026-05-13T20:00:00.000Z",
                  "apiVersion": "2026-04-01",
                  "bindings": {
                    "assets": true,
                    "kv": false,
                    "ai": true,
                    "vectorize": true,
                    "rateLimiter": false,
                    "metrics": false,
                    "webhookQueue": false,
                    "auditLogKv": false
                  },
                  "checks": [
                    {
                      "name": "kv",
                      "configured": false,
                      "healthy": false,
                      "method": "shape",
                      "error": "binding missing"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/ai/background-remove": {
      "get": {
        "operationId": "backgroundRemoveGet",
        "summary": "Remove image background (not yet implemented)",
        "description": "Isolate the subject of an image on a transparent alpha layer. **This endpoint is documented but not yet implemented** — calls return HTTP 501. Cloudflare Workers AI does not currently include a segmentation/matting model (U^2-Net or rembg-class), so we cannot produce a pixel-accurate alpha mask at the edge.\n\nThe route, request shape, and response envelope are fixed now so clients and agents can integrate ahead of the model landing; when Workers AI adds a segmentation primitive (or we ship one via Workers AI Custom Models), the implementation will swap in without changing this contract.\n\nNearest substitute today: `/api/ai/smart-crop` returns a subject gravity that pairs with `/api/transform?gravity=` for subject-aware framing — not the same as transparent-background removal, but the right tool for most thumbnail-style use cases.",
        "tags": [
          "AI"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Relative asset path of the image to process.",
            "schema": {
              "type": "string",
              "maxLength": 2048
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Bad Request - invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented. Background removal is blocked on a Workers AI segmentation model that does not yet exist in the catalog. The response body includes a `details` entry pointing at the blocking dependency.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": "NotImplemented",
                    "message": "Background removal requires a segmentation model that is not yet available in Cloudflare Workers AI.",
                    "details": [
                      {
                        "code": "BlockedByDependency",
                        "target": "@cf/* segmentation models",
                        "message": "No matting model in Workers AI catalog yet."
                      }
                    ]
                  },
                  "HttpCode": 501,
                  "Message": "Background removal requires a segmentation model that is not yet available in Cloudflare Workers AI."
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "backgroundRemovePost",
        "summary": "Remove image background (not yet implemented)",
        "description": "Isolate the subject of an image on a transparent alpha layer. **This endpoint is documented but not yet implemented** — calls return HTTP 501. Cloudflare Workers AI does not currently include a segmentation/matting model (U^2-Net or rembg-class), so we cannot produce a pixel-accurate alpha mask at the edge.\n\nThe route, request shape, and response envelope are fixed now so clients and agents can integrate ahead of the model landing; when Workers AI adds a segmentation primitive (or we ship one via Workers AI Custom Models), the implementation will swap in without changing this contract.\n\nNearest substitute today: `/api/ai/smart-crop` returns a subject gravity that pairs with `/api/transform?gravity=` for subject-aware framing — not the same as transparent-background removal, but the right tool for most thumbnail-style use cases.",
        "tags": [
          "AI"
        ],
        "security": [
          {
            "AccountKey": []
          },
          {
            "AccessKey": []
          },
          {
            "BearerToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "Relative asset path."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Bad Request - invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 401,
                  "Message": "Unauthorized"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "501": {
            "description": "Not Implemented (same body as GET).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": "NotImplemented",
                    "message": "Background removal requires a segmentation model that is not yet available in Cloudflare Workers AI.",
                    "details": [
                      {
                        "code": "BlockedByDependency",
                        "target": "@cf/* segmentation models",
                        "message": "No matting model in Workers AI catalog yet."
                      }
                    ]
                  },
                  "HttpCode": 501,
                  "Message": "Background removal requires a segmentation model that is not yet available in Cloudflare Workers AI."
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway - upstream returned no usable response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream returned empty response"
                }
              }
            }
          }
        }
      }
    },
    "/api/logs": {
      "get": {
        "operationId": "getLogs",
        "summary": "Stream or fetch operational logs",
        "description": "Returns the worker request log buffered in KV. Use `?stream=1` for SSE; otherwise a JSON page is returned. Useful for live debugging and post-incident analysis.",
        "tags": [
          "Operations"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "parameters": [
          {
            "name": "stream",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "When `true`, returns Server-Sent Events instead of a JSON snapshot."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "description": "Max records to return (JSON mode only)."
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Filter to records emitted at or after this ISO-8601 timestamp."
          }
        ],
        "responses": {
          "200": {
            "description": "JSON log page (or SSE stream).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "records": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "count": {
                      "type": "integer"
                    },
                    "cursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "SSE: each line is a JSON log record."
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "503": {
            "description": "KV binding unavailable."
          }
        }
      }
    },
    "/api/pipeline": {
      "post": {
        "operationId": "pipelineIngest",
        "summary": "Scaffold a zone or stock asset from a single SVG",
        "description": "Single-SVG ingest. Generates the full directory tree (logos, banners, icons, favicon, PWA manifest) and commits it via the GitHub API. Two modes: `client` creates a new tenant zone; `stock` adds to the shared stock pool.",
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "mode",
                  "name",
                  "svg"
                ],
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "client",
                      "stock"
                    ],
                    "description": "Pipeline mode."
                  },
                  "name": {
                    "type": "string",
                    "description": "Zone slug (client) or asset slug (stock). lower-kebab-case."
                  },
                  "svg": {
                    "type": "string",
                    "description": "Base64-encoded SVG payload."
                  },
                  "generateIcons": {
                    "type": "boolean",
                    "default": true,
                    "description": "Emit 180/192/512 PNG icons."
                  },
                  "generateBanners": {
                    "type": "boolean",
                    "default": true,
                    "description": "Emit social-share banners."
                  }
                }
              },
              "examples": {
                "client": {
                  "summary": "Scaffold a new tenant zone",
                  "value": {
                    "mode": "client",
                    "name": "newbrand",
                    "svg": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIC4uLg=="
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ingest committed. Returns the commit SHA and the generated file list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "commit": {
                      "type": "string",
                      "description": "Git commit SHA."
                    },
                    "files": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "zone": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed — missing required field, invalid mode, malformed SVG, or oversized payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Missing required field: name."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "Zone or asset slug already exists."
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "GitHub API upstream error."
          }
        }
      }
    },
    "/api/tokens": {
      "get": {
        "operationId": "listTokens",
        "summary": "List API tokens (redacted)",
        "description": "Returns all tokens for the account. Full token values are never exposed — only the prefix, scopes, and timestamps.",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Token list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tokens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "prefix": {
                            "type": "string",
                            "description": "First 8 chars of the token (for identification)."
                          },
                          "scopes": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "expiresAt": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "lastUsedAt": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createToken",
        "summary": "Create a scoped API token",
        "description": "Mints a new API token with the given scopes. The plaintext token is returned **once** in the response — store it; it cannot be retrieved again. SHA-256 hashed at rest.",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "scopes"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Human-readable label."
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "storage:read",
                        "storage:write",
                        "assets:read",
                        "insights:read",
                        "zones:read",
                        "zones:write",
                        "purge:write",
                        "pipeline:write",
                        "webhooks:read",
                        "webhooks:write"
                      ]
                    }
                  },
                  "expiresAt": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Token created. The plaintext token is in the response — store it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "token": {
                      "type": "string",
                      "description": "The plaintext token. Shown once."
                    },
                    "name": {
                      "type": "string"
                    },
                    "scopes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed — missing name, empty or unknown scope, or invalid expiresAt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "scopes must be a non-empty array of allowed scope strings."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "revokeToken",
        "summary": "Revoke an API token",
        "description": "Permanently revokes the token by ID. Subsequent requests using this token return 401.",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token ID."
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked."
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No token with that ID."
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List registered webhooks",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhooks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri"
                          },
                          "events": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "active": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        },
        "description": "Returns metadata for every webhook registered against the account: id, target URL, subscribed events, creation timestamp, and active flag."
      },
      "post": {
        "operationId": "registerWebhook",
        "summary": "Register a webhook",
        "description": "Subscribes the given URL to one or more event types. Deliveries are signed (HMAC-SHA256) and fan-out via a Cloudflare Queue + DLQ for at-least-once semantics. Failed deliveries are retried with exponential backoff.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "events"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "HTTPS endpoint to receive event payloads."
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "asset.created",
                        "asset.deleted",
                        "asset.updated",
                        "zone.created",
                        "zone.deleted",
                        "purge.completed",
                        "pipeline.completed"
                      ]
                    }
                  },
                  "secret": {
                    "type": "string",
                    "description": "Optional HMAC signing secret. If omitted, one is generated and returned."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook registered.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "secret": {
                      "type": "string",
                      "description": "HMAC signing secret. Returned once."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed — missing URL, non-HTTPS target, or empty/unknown event types.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "url must be an HTTPS URI; at least one event must be subscribed."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Delete a webhook",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "AccountKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No webhook with that ID."
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        },
        "description": "Permanently removes a webhook by ID. Future deliveries for the subscribed events stop immediately."
      }
    },
    "/api/passkeys": {
      "get": {
        "operationId": "listPasskeys",
        "summary": "List registered passkeys",
        "description": "Returns metadata for every registered passkey for the authenticated user. Credential IDs are exposed; the raw public keys are not.",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "SessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Passkey list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "passkeys": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "lastUsedAt": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "deviceType": {
                            "type": "string",
                            "enum": [
                              "single_device",
                              "multi_device"
                            ],
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "revokePasskey",
        "summary": "Revoke a passkey",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "SessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked."
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No passkey with that ID."
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        },
        "description": "Permanently revokes a passkey by ID. The credential is removed from KV; subsequent authentication attempts with it fail."
      }
    },
    "/api/passkeys/register/begin": {
      "post": {
        "operationId": "passkeyRegisterBegin",
        "summary": "Start passkey registration — get a challenge",
        "description": "Returns a WebAuthn `PublicKeyCredentialCreationOptions` payload. Pass the resulting credential to `/api/passkeys/register/complete`.",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "SessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Registration options.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "WebAuthn PublicKeyCredentialCreationOptions."
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/passkeys/register/complete": {
      "post": {
        "operationId": "passkeyRegisterComplete",
        "summary": "Complete passkey registration",
        "description": "Verifies the WebAuthn attestation, stores the credential, and returns the persisted passkey metadata.",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "SessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "credential",
                  "name"
                ],
                "properties": {
                  "credential": {
                    "type": "object",
                    "description": "WebAuthn AuthenticatorAttestationResponse."
                  },
                  "name": {
                    "type": "string",
                    "description": "Human-readable label (e.g. \"MacBook Pro\")."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Passkey registered."
          },
          "400": {
            "description": "Invalid attestation."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/passkeys/auth/begin": {
      "post": {
        "operationId": "passkeyAuthBegin",
        "summary": "Start passkey authentication — get a challenge",
        "description": "Returns a WebAuthn `PublicKeyCredentialRequestOptions` payload. Public endpoint (no session required).",
        "tags": [
          "Auth"
        ],
        "responses": {
          "200": {
            "description": "Authentication options.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "WebAuthn PublicKeyCredentialRequestOptions."
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — invalid parameters or malformed input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 400,
                  "Message": "Invalid request parameters"
                }
              }
            }
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    },
    "/api/passkeys/auth/complete": {
      "post": {
        "operationId": "passkeyAuthComplete",
        "summary": "Complete passkey authentication",
        "description": "Verifies the assertion. On success, sets the `cdn_session` cookie (HMAC-signed, HttpOnly, Secure, 7-day TTL).",
        "tags": [
          "Auth"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "credential"
                ],
                "properties": {
                  "credential": {
                    "type": "object",
                    "description": "WebAuthn AuthenticatorAssertionResponse."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Authenticated. `Set-Cookie: cdn_session=...` on the response.",
            "headers": {
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "HMAC-signed session cookie."
              }
            }
          },
          "400": {
            "description": "Invalid assertion."
          },
          "401": {
            "description": "Assertion verification failed."
          },
          "429": {
            "description": "Rate Limited — too many requests. Retry after the cooldown period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 429,
                  "Message": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error — unexpected failure at the edge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 500,
                  "Message": "Internal server error"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway — upstream service (GitHub/Cloudflare API) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "HttpCode": 502,
                  "Message": "Upstream service error"
                }
              }
            }
          }
        }
      }
    }
  }
}
