{
  "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"
                }
              }
            }
          }
        }
      }
    }
  }
}
