{
  "openapi": "3.1.0",
  "info": {
    "title": "Faux IPFS",
    "version": "0.1.0",
    "description": "A private IPFS gateway on a Cloudflare Worker, R2 and KV. No IPFS node."
  },
  "servers": [
    {
      "url": "https://ipfs.slopscore.org"
    }
  ],
  "components": {
    "securitySchemes": {
      "owner": {
        "type": "http",
        "scheme": "bearer",
        "description": "OWNER_TOKEN"
      },
      "gateway": {
        "type": "apiKey",
        "in": "query",
        "name": "gatewayToken",
        "description": "GATEWAY_TOKEN, when set"
      }
    }
  },
  "paths": {
    "/ipfs/{cid}": {
      "get": {
        "summary": "Read a pinned file, or a folder (redirects to the slash form, then serves index.html or a listing). Bytes are checked against the CID as they stream, unless verify=false.",
        "security": [
          {
            "gateway": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "cid",
            "in": "path",
            "description": "CIDv0 (Qm...) or CIDv1 (bafy..., bafk...)",
            "required": true
          },
          {
            "name": "verify",
            "in": "query",
            "description": "false = pass the bytes through without hashing (default from VERIFY_DEFAULT)",
            "required": false
          },
          {
            "name": "download",
            "in": "query",
            "description": "true = Content-Disposition: attachment",
            "required": false
          },
          {
            "name": "filename",
            "in": "query",
            "description": "name for the download",
            "required": false
          },
          {
            "name": "format",
            "in": "query",
            "description": "raw = the root block, for clients that verify it themselves",
            "required": false
          },
          {
            "name": "gatewayToken",
            "in": "query",
            "description": "needed when GATEWAY_TOKEN is set (also pinataGatewayToken, or the x-gateway-token header)",
            "required": false
          },
          {
            "name": "Range",
            "in": "header",
            "description": "bytes=a-b, answered 206",
            "required": false
          }
        ],
        "responses": {
          "default": {
            "description": "200/206 the file, with Etag, X-Ipfs-Path, X-Ipfs-Roots, immutable Cache-Control, X-Faux-Verify: verified|skipped and X-Faux-Cache: HIT|MISS (verified responses are kept in the edge cache). 404 if not pinned here."
          }
        }
      },
      "head": {
        "summary": "The same headers as GET, no body.",
        "security": [
          {
            "gateway": []
          },
          {}
        ],
        "parameters": [],
        "responses": {
          "default": {
            "description": "200"
          }
        }
      }
    },
    "/ipfs/{cid}/{path}": {
      "get": {
        "summary": "A file or subfolder inside a pinned folder. Every folder node on the way is hashed against the CID that points to it.",
        "security": [
          {
            "gateway": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "description": "e.g. img/photo.jpg; a folder path ends in /",
            "required": true
          },
          {
            "name": "verify",
            "in": "query",
            "description": "false = no hashing",
            "required": false
          }
        ],
        "responses": {
          "default": {
            "description": "200/206 the file; a folder gives its index.html or a listing; 404 if the path isn't in the folder"
          }
        }
      }
    },
    "/api/files": {
      "post": {
        "summary": "Upload and pin a file. Returns its CID, the same one `ipfs add` would give.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "description": "multipart/form-data: file (required), name, cidVersion (0|1), keyvalues (JSON). For a folder, send several file parts whose filenames carry the path (site/index.html, site/img/a.png): the folder gets the CID `ipfs add -r` gives. Or a raw body with ?name=&cidVersion="
        },
        "responses": {
          "default": {
            "description": "201 {cid, kind (file|dir), name, size, type, cidVersion, created, keyvalues, files (folders), url, isDuplicate}; 200 with isDuplicate: true if already pinned"
          }
        }
      },
      "get": {
        "summary": "List pinned files.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "up to 1000 (default 100)",
            "required": false
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "from the previous page",
            "required": false
          }
        ],
        "responses": {
          "default": {
            "description": "200 {files: [{cid, name, size, created}], cursor}"
          }
        }
      }
    },
    "/api/files/{cid}": {
      "get": {
        "summary": "One file's record.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "responses": {
          "default": {
            "description": "200 the record; 404 if not pinned"
          }
        }
      },
      "patch": {
        "summary": "Rename, or merge keyvalues. The CID never changes.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "description": "JSON {name?, keyvalues?}"
        },
        "responses": {
          "default": {
            "description": "200 the record"
          }
        }
      },
      "delete": {
        "summary": "Unpin and delete a file or folder, with all its stored objects and blocks.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "responses": {
          "default": {
            "description": "200 {deleted}; 404 if not pinned"
          }
        }
      }
    },
    "/pinning/pinFileToIPFS": {
      "post": {
        "summary": "Legacy pinning-API alias: upload (file, pinataMetadata, pinataOptions.cidVersion), for existing SDK calls.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "description": "multipart/form-data"
        },
        "responses": {
          "default": {
            "description": "200 {IpfsHash, PinSize, Timestamp, isDuplicate}"
          }
        }
      }
    },
    "/pinning/pinJSONToIPFS": {
      "post": {
        "summary": "Legacy pinning-API alias: pin a JSON value.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "description": "JSON {pinataContent, pinataMetadata, pinataOptions}"
        },
        "responses": {
          "default": {
            "description": "200 {IpfsHash, PinSize, Timestamp, isDuplicate}"
          }
        }
      }
    },
    "/pinning/unpin/{cid}": {
      "delete": {
        "summary": "Legacy pinning-API alias: delete.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "responses": {
          "default": {
            "description": "200 OK"
          }
        }
      }
    },
    "/data/pinList": {
      "get": {
        "summary": "Legacy pinning-API alias: list.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "responses": {
          "default": {
            "description": "200 {count, rows: [{ipfs_pin_hash, size, date_pinned, metadata}]}"
          }
        }
      }
    },
    "/data/testAuthentication": {
      "get": {
        "summary": "Check a token.",
        "security": [
          {
            "owner": []
          }
        ],
        "parameters": [],
        "responses": {
          "default": {
            "description": "200"
          }
        }
      }
    },
    "/demo/pin": {
      "post": {
        "summary": "Demo only (when DEMO is set): pin a short text. Up to 5,000 characters of English letters, numbers, spaces, newlines and . , ! ? ' \" - : ; ( ).",
        "security": [],
        "parameters": [],
        "requestBody": {
          "description": "JSON {text}"
        },
        "responses": {
          "default": {
            "description": "201/200 {cid, url, size, isDuplicate}; 400 if the text breaks the rules; 404 when DEMO is off"
          }
        }
      }
    }
  }
}