{
  "openapi": "3.1.0",
  "info": {
    "title": "PentaFabric Storage \u00b7 Portable Workspace API",
    "version": "1.3.0",
    "description": "Scoped read-only metadata API. No payments, file bytes, deletion, automated migration, or OAuth discovery. Named-recipient links require verified sign-in."
  },
  "servers": [
    {
      "url": "https://crownthrive-storage-fabric.vercel.app"
    }
  ],
  "components": {
    "securitySchemes": {
      "FabricKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "pfk_ followed by 64 lowercase hex characters",
        "description": "Create an expiring, revocable key in API & MCP. Do not use a provider secret or forward a broad identity token."
      }
    }
  },
  "paths": {
    "/api/fabric": {
      "get": {
        "operationId": "readFabric",
        "security": [
          {
            "FabricKey": []
          }
        ],
        "parameters": [
          {
            "name": "resource",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "files",
                "passport",
                "integrations"
              ],
              "default": "files"
            }
          },
          {
            "name": "after",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "query",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authorized metadata page. Follow next_after while has_more is true."
          },
          "400": {
            "description": "Invalid or unsupported parameters."
          },
          "401": {
            "description": "A valid API key is required."
          },
          "403": {
            "description": "Key revoked, expired, or lacking the matching read scope."
          },
          "429": {
            "description": "Tenant request allowance exceeded; retry after 60 seconds."
          },
          "503": {
            "description": "Temporary service failure; no destructive side effects."
          }
        }
      }
    },
    "/api/suite": {
      "get": {
        "summary": "Read authenticated workbench or operator workflow state",
        "description": "op=workbench uses a customer session JWT; op=operations additionally requires native operator membership. Not a read-only API-key endpoint.",
        "parameters": [
          {
            "name": "op",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "workbench",
                "operations"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authorized workspace or operator view"
          },
          "401": {
            "description": "No authenticated session"
          },
          "403": {
            "description": "Insufficient permission"
          }
        }
      },
      "post": {
        "summary": "Versioned rights/context and local processing receipts",
        "description": "Fixed op allowlist: governance, governance-save, governance-submit, process-record. Requires customer session JWT. Server derives tenant; no automatic approval, publication, upload or billing.",
        "parameters": [
          {
            "name": "op",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "governance",
                "governance-save",
                "governance-submit",
                "process-record",
                "governance-export"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Saved declaration, queued review, or client-reported processing metadata"
          },
          "400": {
            "description": "Invalid field, revision or replay"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "File does not belong to this tenant"
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "mcpMessage",
        "security": [
          {
            "FabricKey": []
          }
        ],
        "description": "Stateless JSON-RPC Streamable HTTP with manual Bearer-key authentication. Protocol versions 2025-06-18 and 2025-03-26. No server SSE stream; GET returns 405. Tools are filtered by the key scopes.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "const": "2.0"
                  },
                  "id": {
                    "type": [
                      "string",
                      "number",
                      "null"
                    ]
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "initialize",
                      "ping",
                      "tools/list",
                      "tools/call",
                      "notifications/initialized",
                      "notifications/cancelled"
                    ]
                  },
                  "params": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result or error."
          },
          "202": {
            "description": "Accepted notification."
          },
          "401": {
            "description": "Scoped key required."
          },
          "403": {
            "description": "Authorization denied."
          }
        }
      }
    },
    "/api/qr": {
      "post": {
        "operationId": "renderLocatorQR",
        "description": "Renders a valid PentaFabric site/file/share locator as SVG. Does not grant access or encode an API key. No external QR processor.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "additionalProperties": false,
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 240
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scannable SVG image.",
            "content": {
              "image/svg+xml": {}
            }
          },
          "400": {
            "description": "Not an accepted PentaFabric locator."
          },
          "413": {
            "description": "Request exceeds 1024 bytes."
          }
        }
      }
    }
  },
  "x-scopes": {
    "files": "files:read",
    "passport": "passport:read",
    "integrations": "integrations:read"
  }
}