{
  "openapi": "3.1.0",
  "info": {
    "title": "KERNIT Hyperlinker API",
    "version": "2026-05-12",
    "summary": "Reviewable DOCX citation and cross-reference hyperlinking API.",
    "description": "The KERNIT Hyperlinker API scans DOCX manuscripts, returns reviewable citation and cross-reference matches, resolves bibliography evidence, and applies approved links back into editable DOCX output.",
    "license": {
      "name": "Proprietary",
      "url": "https://kernit.org/terms"
    }
  },
  "servers": [
    {
      "url": "https://api.kernit.org",
      "description": "Production API host"
    }
  ],
  "x-kernitContract": {
    "status": "stable",
    "publicRoutePolicy": "Production API calls use bare routes on https://api.kernit.org. Do not prefix public calls with /api.",
    "breakingChangePolicy": "Removing fields, changing required request fields, or changing endpoint semantics requires a documented version track before customer integrations are expected to migrate.",
    "additiveChangePolicy": "New optional response fields and optional request fields can ship inside the current contract.",
    "authPolicy": "Document-processing routes use Bearer API keys. Dashboard and team-management routes can use browser session auth where documented.",
    "maxDocxBytes": 26214400,
    "supportContext": ["endpoint", "status", "requestId", "scanFingerprint", "settingsHash"]
  },
  "tags": [
    {
      "name": "Hyperlinker",
      "description": "DOCX scan, resolver, and apply routes."
    },
    {
      "name": "Keys",
      "description": "Individual and organization API key management."
    },
    {
      "name": "Organizations",
      "description": "Team presets, usage, members, and billing surfaces."
    },
    {
      "name": "Docs",
      "description": "Admin-only documentation analytics and release-quality surfaces."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/hyperlink-scan": {
      "post": {
        "operationId": "scanHyperlinkDocx",
        "tags": ["Hyperlinker"],
        "summary": "Scan a DOCX for reviewable links",
        "description": "Reads a DOCX manuscript and returns citation, bibliography, DOI, figure, table, equation, section, appendix, algorithm, and listing review data without modifying the file.",
        "x-docsPath": "/docs/api/scan",
        "x-billing": "Scan is review preparation and normally does not consume final apply allowance.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Valid Microsoft Word DOCX package. Maximum size is 25 MB."
                  },
                  "settings": {
                    "type": "string",
                    "description": "JSON string matching HyperlinkSettings. Defaults are conservative."
                  }
                }
              },
              "encoding": {
                "settings": {
                  "contentType": "application/json"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Review packet with scan token and candidate links.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanPacket"
                },
                "examples": {
                  "ready": {
                    "summary": "Ready scan packet",
                    "value": {
                      "scanFingerprint": "sha256:2a71...",
                      "scanToken": "eyJhbGciOiJIUzI1NiIs...",
                      "summary": {
                        "estimatedLinkCount": 47,
                        "unmatchedCount": 3,
                        "targetCount": 28
                      },
                      "matches": [
                        {
                          "refId": "r1",
                          "sourceText": "[1]",
                          "status": "ready",
                          "targetId": "b1"
                        }
                      ],
                      "targets": [
                        {
                          "targetId": "b1",
                          "label": "Reference 1",
                          "type": "reference"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "413": { "$ref": "#/components/responses/FileTooLarge" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/hyperlink-crossref": {
      "post": {
        "operationId": "resolveCrossrefEvidence",
        "tags": ["Hyperlinker"],
        "summary": "Resolve bibliography entries with Crossref evidence",
        "description": "Extracts references from the DOCX, resolves DOI/title evidence, detects CSL style signals when enabled, and returns resolver metadata that can be reviewed before apply. Heavy resolver calls can stream progress before the terminal JSON report.",
        "x-docsPath": "/docs/api/resolve",
        "x-billing": "Resolver behavior is governed by user or organization plan and allowance.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Valid DOCX file to inspect."
                  },
                  "settings": {
                    "type": "string",
                    "description": "JSON string matching HyperlinkSettings. Set doi and crossref true for resolver work."
                  },
                  "scanFingerprint": {
                    "type": "string",
                    "description": "Fingerprint returned by /hyperlink-scan. Recommended so resolver output aligns with apply."
                  }
                }
              },
              "encoding": {
                "settings": {
                  "contentType": "application/json"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resolver report with DOI/title evidence, scan state, and optional style-detection metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResolverReport"
                },
                "examples": {
                  "resolved": {
                    "value": {
                      "scanFingerprint": "sha256:2a71...",
                      "scanToken": "eyJhbGciOiJIUzI1NiIs...",
                      "resolvedWorks": {
                        "r1": {
                          "doi": "10.1234/example",
                          "title": "Example resolved article",
                          "confidence": 0.94,
                          "citationImpact": "link-only-safe"
                        }
                      },
                      "references": [
                        {
                          "refId": "r1",
                          "index": 1,
                          "refText": "Example Author. Example resolved article. Journal. 2024.",
                          "existingDoi": null
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "413": { "$ref": "#/components/responses/FileTooLarge" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/hyperlink-apply": {
      "post": {
        "operationId": "applyReviewedHyperlinks",
        "tags": ["Hyperlinker"],
        "summary": "Apply reviewed links to a DOCX",
        "description": "Writes approved citation, cross-reference, DOI, URL, and resolver decisions into the same DOCX used during scan. The route verifies scanToken, scanFingerprint, file hash, settings hash, persisted metadata hash, caller, and graph state before returning final output.",
        "x-docsPath": "/docs/api/apply",
        "x-billing": "Consumes apply or document-processing allowance after scan-token validation.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file", "settings", "scanToken", "scanFingerprint", "decisions"],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Same DOCX package used during scan."
                  },
                  "settings": {
                    "type": "string",
                    "description": "JSON string matching the settings used during scan."
                  },
                  "scanToken": {
                    "type": "string",
                    "description": "Signed token returned by scan or resolver."
                  },
                  "scanFingerprint": {
                    "type": "string",
                    "description": "Fingerprint returned by scan or resolver."
                  },
                  "decisions": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/ReviewDecision"
                    },
                    "description": "JSON array of ReviewDecision objects."
                  },
                  "resolvedWorks": {
                    "type": "string",
                    "description": "Optional JSON resolver evidence to apply when approved."
                  },
                  "cslFile": {
                    "type": "string",
                    "format": "binary",
                    "description": "Optional CSL XML file for controlled bibliography rewrite."
                  },
                  "detectedCslId": {
                    "type": "string",
                    "description": "Optional detected CSL style id."
                  },
                  "applyBibRewrite": {
                    "type": "string",
                    "enum": ["true", "false"],
                    "description": "Set true only when bibliography rewrite is explicitly approved."
                  }
                }
              },
              "encoding": {
                "settings": { "contentType": "application/json" },
                "decisions": { "contentType": "application/json" },
                "resolvedWorks": { "contentType": "application/json" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Base64 DOCX and apply statistics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApplyResult"
                },
                "examples": {
                  "linkedDocx": {
                    "value": {
                      "docx": "UEsDBBQAAAA...",
                      "linkCount": 47,
                      "statCounts": { "cite": 23, "fig": 6, "tbl": 8 },
                      "appliedDecisions": 4,
                      "unmatched": []
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/ScanTokenInvalid" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "413": { "$ref": "#/components/responses/FileTooLarge" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/hyperlink": {
      "post": {
        "operationId": "hyperlinkDocxDirect",
        "tags": ["Hyperlinker"],
        "summary": "One-step DOCX hyperlinking",
        "description": "Uploads a DOCX and returns linked output without an intermediate review step. Use scan/resolve/apply when wrong-link correction matters.",
        "x-docsPath": "/docs/api/direct-hyperlink",
        "x-billing": "Consumes document-processing allowance.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Valid DOCX package."
                  },
                  "settings": {
                    "type": "string",
                    "description": "JSON string matching HyperlinkSettings."
                  }
                }
              },
              "encoding": {
                "settings": { "contentType": "application/json" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Base64 DOCX and link statistics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApplyResult"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "413": { "$ref": "#/components/responses/FileTooLarge" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/api-keys": {
      "get": {
        "operationId": "listApiKeys",
        "tags": ["Keys"],
        "summary": "List individual API keys",
        "description": "Lists API keys owned by the signed-in user. This route uses browser session auth.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "responses": {
          "200": {
            "description": "Key list.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApiKeyList" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "post": {
        "operationId": "createApiKey",
        "tags": ["Keys"],
        "summary": "Create an individual API key",
        "description": "Creates a live API key for the signed-in user when API access policy allows it.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateKeyRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "New API key. The full key is only returned once.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/NewApiKey" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "delete": {
        "operationId": "revokeApiKey",
        "tags": ["Keys"],
        "summary": "Revoke an individual API key",
        "description": "Revokes an API key owned by the signed-in user. The key id is passed as an id query parameter.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": { "type": "string" },
            "description": "API key id."
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OkResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/org-keys": {
      "get": {
        "operationId": "listOrgKeys",
        "tags": ["Keys", "Organizations"],
        "summary": "List organization API keys",
        "description": "Lists active organization API keys for managers and owners.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "parameters": [
          {
            "name": "include_inactive",
            "in": "query",
            "required": false,
            "schema": { "type": "boolean" },
            "description": "Include revoked keys when true."
          }
        ],
        "responses": {
          "200": {
            "description": "Organization keys.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApiKeyList" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "post": {
        "operationId": "createOrgKey",
        "tags": ["Keys", "Organizations"],
        "summary": "Create organization API key",
        "description": "Creates an organization API key for managers or owners.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateKeyRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "New organization key. The full key is only returned once.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/NewOrgKey" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "delete": {
        "operationId": "revokeOrgKey",
        "tags": ["Keys", "Organizations"],
        "summary": "Revoke organization API key",
        "description": "Revokes an organization API key by id.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["key_id"],
                "properties": {
                  "key_id": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Revoked.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OkResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/org-presets": {
      "get": {
        "operationId": "listOrgPresets",
        "tags": ["Organizations"],
        "summary": "List shared organization presets",
        "description": "Loads shared hyperlink settings presets for the signed-in user's organization.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "responses": {
          "200": {
            "description": "Preset list.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OrgPresetList" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      },
      "post": {
        "operationId": "createOrgPreset",
        "tags": ["Organizations"],
        "summary": "Create shared organization preset",
        "description": "Creates a named hyperlink settings preset for managers or owners.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/OrgPresetWrite" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created preset.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OrgPresetCreated" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/org-usage": {
      "get": {
        "operationId": "listOrgUsage",
        "tags": ["Organizations"],
        "summary": "List organization usage",
        "description": "Returns paginated organization API usage rows.",
        "x-docsPath": "/docs/api/team-admin",
        "security": [{ "sessionAuth": [] }],
        "parameters": [
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } }
        ],
        "responses": {
          "200": {
            "description": "Usage rows.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OrgUsageList" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/admin-docs-insights": {
      "get": {
        "operationId": "getAdminDocsInsights",
        "tags": ["Docs"],
        "summary": "Get hosted docs analytics summary",
        "description": "Returns an admin-only aggregate view of sanitized documentation events including top pages, searches, zero-result searches, playground responses, playground errors, feedback totals, and recent events.",
        "x-docsPath": "/docs/api/insights",
        "security": [{ "sessionAuth": [] }],
        "parameters": [
          { "name": "days", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 365, "default": 30 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 5000, "default": 1000 } }
        ],
        "responses": {
          "200": {
            "description": "Docs analytics summary.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/DocsInsightsResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "default": { "$ref": "#/components/responses/ServerError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "KERNIT API key, for example sk_kernit_live_..."
      },
      "sessionAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Authenticated browser session token for dashboard/team routes."
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string" },
          "reason": { "type": ["string", "null"] },
          "hint": { "type": "string" },
          "status": { "type": "string" },
          "requestId": { "type": "string", "description": "KERNIT request id when available for support correlation." },
          "retry_after": { "type": "integer", "description": "Seconds to wait before another request when rate limited." },
          "retryAfter": { "type": "integer", "description": "Camel-case retry delay used by some rate-limit helpers." }
        },
        "additionalProperties": true
      },
      "HyperlinkSettings": {
        "type": "object",
        "properties": {
          "preset_id": { "type": ["string", "null"], "description": "Optional organization preset id." },
          "refs": { "type": "boolean", "default": true },
          "citeStyle": { "type": "string", "enum": ["auto", "number", "author-year", "superscript", "off"], "default": "auto" },
          "citeLinkScope": { "type": "string", "enum": ["author-year", "full"], "default": "author-year" },
          "citeIncludePages": { "type": "boolean", "default": false },
          "figures": { "type": "string", "enum": ["number", "numbersub", "full", "off"], "default": "number" },
          "tables": { "type": "string", "enum": ["number", "numbersub", "full", "off"], "default": "number" },
          "equations": { "type": "string", "enum": ["number", "numbersub", "full", "off"], "default": "number" },
          "sections": { "type": "string", "enum": ["number", "full", "off"], "default": "number" },
          "algorithms": { "type": "string", "enum": ["number", "numbersub", "full", "off"], "default": "off" },
          "listings": { "type": "string", "enum": ["number", "numbersub", "full", "off"], "default": "off" },
          "appendices": { "type": "string", "enum": ["number", "full", "off"], "default": "number" },
          "doi": { "type": "boolean", "default": false },
          "crossref": { "type": "boolean", "default": false },
          "refTitleLink": { "type": "boolean", "default": false },
          "suffixDisambiguationOptIn": { "type": "boolean", "default": false },
          "linkColor": { "type": "string", "default": "#0077BD" },
          "xrefLinkColor": { "type": "string", "default": "#0077BD" },
          "urlFont": { "type": "string", "default": "" }
        },
        "additionalProperties": true
      },
      "ScanPacket": {
        "type": "object",
        "required": ["scanFingerprint", "matches", "targets"],
        "properties": {
          "scanFingerprint": { "type": "string" },
          "scanToken": { "type": "string" },
          "summary": {
            "type": "object",
            "properties": {
              "estimatedLinkCount": { "type": "integer" },
              "unmatchedCount": { "type": "integer" },
              "targetCount": { "type": "integer" }
            },
            "additionalProperties": true
          },
          "matches": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ReviewMatch" }
          },
          "targets": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ReviewTarget" }
          },
          "synchronizedCitationUpdatesEnabled": { "type": "boolean" },
          "persistedMetadata": { "type": ["object", "null"], "additionalProperties": true }
        },
        "additionalProperties": true
      },
      "ReviewMatch": {
        "type": "object",
        "properties": {
          "refId": { "type": "string" },
          "sourceText": { "type": "string" },
          "status": { "type": "string", "enum": ["ready", "unmatched", "low_confidence", "held", "identity_change"] },
          "targetId": { "type": "string" },
          "kind": { "type": "string" },
          "confidence": { "type": "number" }
        },
        "additionalProperties": true
      },
      "ReviewTarget": {
        "type": "object",
        "properties": {
          "targetId": { "type": "string" },
          "label": { "type": "string" },
          "type": { "type": "string" }
        },
        "additionalProperties": true
      },
      "ReviewDecision": {
        "type": "object",
        "required": ["refId", "status"],
        "properties": {
          "refId": { "type": "string" },
          "status": { "type": "string", "enum": ["approved", "skipped", "retargeted", "link_only"] },
          "targetId": { "type": "string" },
          "doi": { "type": "string" },
          "reason": { "type": "string" }
        },
        "additionalProperties": true
      },
      "ResolverReport": {
        "type": "object",
        "properties": {
          "scanFingerprint": { "type": "string" },
          "scanToken": { "type": "string" },
          "references": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ReferenceCandidate" }
          },
          "resolvedWorks": {
            "type": "object",
            "additionalProperties": { "$ref": "#/components/schemas/ResolvedWork" }
          },
          "detectedCslId": { "type": ["string", "null"] },
          "styleDetection": { "type": ["object", "null"], "additionalProperties": true }
        },
        "additionalProperties": true
      },
      "ReferenceCandidate": {
        "type": "object",
        "properties": {
          "refId": { "type": "string" },
          "index": { "type": "integer" },
          "refText": { "type": "string" },
          "refTextHtml": { "type": "string" },
          "author": { "type": ["string", "null"] },
          "year": { "type": ["string", "null"] },
          "title": { "type": ["string", "null"] },
          "existingDoi": { "type": ["string", "null"] },
          "existingUrl": { "type": ["string", "null"] }
        },
        "additionalProperties": true
      },
      "ResolvedWork": {
        "type": "object",
        "properties": {
          "doi": { "type": "string" },
          "title": { "type": "string" },
          "confidence": { "type": "number" },
          "citationImpact": { "type": "string" },
          "transactionPlan": { "type": ["object", "null"], "additionalProperties": true }
        },
        "additionalProperties": true
      },
      "ApplyResult": {
        "type": "object",
        "required": ["docx", "linkCount"],
        "properties": {
          "docx": { "type": "string", "description": "Base64-encoded DOCX package." },
          "linkCount": { "type": "integer" },
          "statCounts": { "type": "object", "additionalProperties": { "type": "integer" } },
          "stats": { "type": "object", "additionalProperties": true },
          "unmatched": { "type": "array", "items": { "type": "object", "additionalProperties": true } },
          "appliedDecisions": { "type": "integer" }
        },
        "additionalProperties": true
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "key_prefix": { "type": "string" },
          "prefix": { "type": "string" },
          "is_active": { "type": "boolean" },
          "last_used_at": { "type": ["string", "null"], "format": "date-time" },
          "total_docs_processed": { "type": "integer" },
          "created_at": { "type": "string", "format": "date-time" },
          "expires_at": { "type": ["string", "null"], "format": "date-time" }
        },
        "additionalProperties": true
      },
      "ApiKeyList": {
        "type": "object",
        "properties": {
          "keys": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiKey" }
          }
        }
      },
      "CreateKeyRequest": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "maxLength": 100 }
        }
      },
      "NewApiKey": {
        "type": "object",
        "properties": {
          "key": { "type": "string" },
          "id": { "type": "string" },
          "name": { "type": "string" },
          "prefix": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" },
          "trial_credits_granted": { "type": "integer" },
          "api_credits": { "type": "integer" }
        }
      },
      "NewOrgKey": {
        "type": "object",
        "properties": {
          "key": { "type": "string" },
          "id": { "type": "string" },
          "name": { "type": "string" },
          "key_prefix": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "OrgPreset": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "settings": { "$ref": "#/components/schemas/HyperlinkSettings" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        },
        "additionalProperties": true
      },
      "OrgPresetList": {
        "type": "object",
        "properties": {
          "presets": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/OrgPreset" }
          }
        }
      },
      "OrgPresetWrite": {
        "type": "object",
        "required": ["name", "settings"],
        "properties": {
          "name": { "type": "string", "maxLength": 100 },
          "settings": { "$ref": "#/components/schemas/HyperlinkSettings" }
        }
      },
      "OrgPresetCreated": {
        "type": "object",
        "properties": {
          "preset": { "$ref": "#/components/schemas/OrgPreset" }
        }
      },
      "OrgUsageList": {
        "type": "object",
        "properties": {
          "usage": {
            "type": "array",
            "items": { "type": "object", "additionalProperties": true }
          },
          "total": { "type": "integer" },
          "page": { "type": "integer" },
          "limit": { "type": "integer" }
        }
      },
      "DocsInsightCount": {
        "type": "object",
        "required": ["key", "count"],
        "properties": {
          "key": { "type": "string" },
          "count": { "type": "integer" }
        }
      },
      "DocsInsightsSummary": {
        "type": "object",
        "required": ["generated_at", "total_events", "unique_sessions", "by_type", "top_pages", "top_searches", "zero_result_searches", "playground", "feedback", "recent"],
        "properties": {
          "generated_at": { "type": "string", "format": "date-time" },
          "total_events": { "type": "integer" },
          "unique_sessions": { "type": "integer" },
          "by_type": { "type": "object", "additionalProperties": { "type": "integer" } },
          "top_pages": { "type": "array", "items": { "$ref": "#/components/schemas/DocsInsightCount" } },
          "top_searches": { "type": "array", "items": { "$ref": "#/components/schemas/DocsInsightCount" } },
          "zero_result_searches": { "type": "array", "items": { "$ref": "#/components/schemas/DocsInsightCount" } },
          "playground": {
            "type": "object",
            "properties": {
              "responses_by_status": { "type": "object", "additionalProperties": { "type": "integer" } },
              "top_errors": { "type": "array", "items": { "$ref": "#/components/schemas/DocsInsightCount" } }
            }
          },
          "feedback": {
            "type": "object",
            "properties": {
              "yes": { "type": "integer" },
              "no": { "type": "integer" }
            }
          },
          "recent": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "event_type": { "type": "string" },
                "path": { "type": "string" },
                "detail": { "type": "object", "additionalProperties": true },
                "created_at": { "type": ["string", "null"], "format": "date-time" }
              },
              "additionalProperties": false
            }
          }
        },
        "additionalProperties": false
      },
      "DocsInsightsResponse": {
        "type": "object",
        "required": ["window_days", "limit", "insights"],
        "properties": {
          "window_days": { "type": "integer" },
          "limit": { "type": "integer" },
          "insights": { "$ref": "#/components/schemas/DocsInsightsSummary" }
        },
        "additionalProperties": false
      },
      "OkResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "success": { "type": "boolean" }
        },
        "additionalProperties": false
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request shape, missing file, invalid JSON, or rejected DOCX.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "invalidJson": { "value": { "error": "Invalid JSON in form data" } },
              "docxRejected": { "value": { "error": "DOCX rejected", "reason": "missing-document-xml" } }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid authorization.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "missing": { "value": { "error": "Missing authorization header" } },
              "session": { "value": { "error": "Unauthorized" } }
            }
          }
        }
      },
      "ScanTokenInvalid": {
        "description": "Scan token missing, invalid, or not aligned with file/settings/graph/caller state.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "missing": { "value": { "error": "scan token invalid", "reason": "missing" } },
              "fileMismatch": { "value": { "error": "scan token invalid", "reason": "file_mismatch" } },
              "settingsMismatch": { "value": { "error": "scan token invalid", "reason": "settings_mismatch" } },
              "graphMismatch": { "value": { "error": "scan token invalid", "reason": "graph_mismatch" } }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Authenticated caller does not have access.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "paidPlan": { "value": { "error": "hyperlinker_requires_paid_plan" } },
              "role": { "value": { "error": "Manager or owner role required" } }
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "No credits or plan allowance available.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "credits": { "value": { "error": "No credits remaining" } }
            }
          }
        }
      },
      "FileTooLarge": {
        "description": "DOCX exceeds the current 25 MB limit.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "tooLarge": { "value": { "error": "File exceeds 25MB limit" } }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "Conflict": {
        "description": "Conflict such as duplicate key name or configured limit reached.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "KERNIT server-side processing is temporarily unavailable or the resolver stream failed.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "serviceUnavailable": { "value": { "error": "Service temporarily unavailable" } }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Per-key or organization request rate limit exceeded.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "rateLimited": { "value": { "error": "Rate limit exceeded", "retry_after": 30 } }
            }
          }
        }
      },
      "ServerError": {
        "description": "Unexpected KERNIT-side service error.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "generic": { "value": { "error": "Processing failed" } }
            }
          }
        }
      }
    }
  }
}
