{
  "openapi": "3.0.3",
  "info": {
    "title": "Scholar Sidekick API",
    "version": "1.2.1",
    "description": "Resolve scholarly identifiers (DOI, PMID, PMCID, ISBN, ISSN/eISSN, arXiv, ADS bibcode, scholarly URLs)\ninto normalized metadata and formatted citations. Supports export to RIS and BibTeX.\n\n## Versioning & deprecation\n\nThe API uses **header-based versioning**. Clients may pin a version with the\noptional `Api-Version` request header (see the `ApiVersion` parameter). The\nAPI currently serves a single version, and the active version tag is\nreturned on **every** response in the `X-Scholar-Transform-Version` header\n(the verifier pipeline additionally returns `X-Scholar-Verify-Version`).\n\n**Deprecation policy:** when a future breaking version ships, the prior\nversion is announced on its responses via the standard `Deprecation` header\nand a `Sunset` header (RFC 8594) giving the retirement date, with a minimum\n180-day overlap before removal. Deprecations are also recorded publicly at\nhttps://scholar-sidekick.com/changelog. This policy is also published in\nmachine-readable form in the `x-api-lifecycle` extension on this document.\n\n## Errors\n\nErrors return the typed `ErrorResponse` envelope (`{ ok: false, error, code }`)\nas `application/json` by default. The stable `code` is also mirrored in the\n`X-Error-Code` response header. Clients that send\n`Accept: application/problem+json` instead receive the same error as an\nRFC 9457 `ProblemDetails` document (`type`/`title`/`status`/`detail`/`code`).\n\n## Idempotency\n\nThe mutating POST routes (`/api/format`, `/api/format-items`, `/api/export`,\n`/api/verify`) accept an optional `Idempotency-Key` request header (see the\n`IdempotencyKey` parameter). When the server has idempotency enabled, a\nrepeated request with the same key and body replays the original response\nverbatim with `Idempotent-Replayed: true`; the same key with a different body\nreturns `422`. These operations are deterministic and side-effect-free, so the\nkey exists purely for retry safety.\n\n## Long-running work\n\nThere is no async-job/polling pattern: the synchronous endpoints complete in a\nsingle request. For incremental/large batches use `POST /api/format/stream`,\nwhich streams newline-delimited JSON (NDJSON) events as records resolve.\n\n## Pagination\n\n`GET /api/csl/styles` is offset-paginated (`limit`/`offset`). Each page returns\nan explicit `nextOffset` (or `null` on the last page) and, when more results\nexist, an RFC 8288 `Link: <…>; rel=\"next\"` response header.\n",
    "termsOfService": "https://scholar-sidekick.com/legal/api-terms",
    "contact": {
      "name": "Scholar Sidekick",
      "email": "support@scholar-sidekick.com",
      "url": "https://scholar-sidekick.com"
    },
    "x-logo": {
      "url": "https://scholar-sidekick.com/icon-512.png",
      "altText": "Scholar Sidekick"
    },
    "license": {
      "name": "Apache-2.0",
      "url": "https://www.apache.org/licenses/LICENSE-2.0"
    },
    "x-api-lifecycle": {
      "versioning": "header",
      "versionHeader": "Api-Version",
      "activeVersionHeader": "X-Scholar-Transform-Version",
      "activeVersion": "2026-08-18",
      "deprecation": {
        "signalHeaders": [
          "Deprecation",
          "Sunset"
        ],
        "sunsetStandard": "RFC 8594",
        "minOverlapDays": 180
      },
      "changelog": "https://scholar-sidekick.com/changelog"
    }
  },
  "servers": [
    {
      "url": "https://scholar-sidekick.com",
      "description": "Production"
    }
  ],
  "security": [
    {},
    {
      "BearerAuth": []
    },
    {
      "RapidApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Health",
      "description": "Service status and diagnostic endpoints."
    },
    {
      "name": "Resolve",
      "description": "Pre-format primitives. Detect scholarly identifiers in free text, and\nresolve one identifier to normalized metadata — without running the\nformatter pipeline.\n"
    },
    {
      "name": "Format",
      "description": "Resolve identifiers and format citations."
    },
    {
      "name": "Export",
      "description": "Export citations to manager-friendly formats."
    },
    {
      "name": "Checks",
      "description": "Retraction and open-access lookups for a single identifier."
    },
    {
      "name": "Verify",
      "description": "Verify a claimed citation against its resolved record (Phase 12i).\nDetects the dominant biomedical fabrication pattern documented in\nTopaz et al. (Lancet 2026, doi:10.1016/S0140-6736(26)00603-3).\n"
    },
    {
      "name": "Styles",
      "description": "Discover and browse available CSL citation styles."
    }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Health check",
        "operationId": "healthCheck",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Auth-Source": {
                "description": "Where the auth came from (first-party, rapidapi, anonymous).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "first-party",
                    "rapidapi",
                    "anonymous"
                  ]
                }
              },
              "X-Auth-Plan": {
                "description": "Effective plan for this request (Free/Developer/Pro/Enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Content-Security-Policy": {
                "description": "CSP controlling resource loading.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Content-Type-Options": {
                "description": "MIME type sniffing prevention.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "nosniff"
                  ]
                }
              },
              "X-Frame-Options": {
                "description": "Clickjacking protection.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "DENY",
                    "SAMEORIGIN"
                  ]
                }
              },
              "Referrer-Policy": {
                "description": "Referrer information policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-referrer",
                    "no-referrer-when-downgrade",
                    "origin",
                    "origin-when-cross-origin",
                    "same-origin",
                    "strict-origin",
                    "strict-origin-when-cross-origin",
                    "unsafe-url"
                  ]
                }
              },
              "Permissions-Policy": {
                "description": "Feature policy controls.",
                "schema": {
                  "type": "string"
                }
              },
              "Cross-Origin-Opener-Policy": {
                "description": "Cross-origin opener policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-origin-allow-popups",
                    "unsafe-none"
                  ]
                }
              },
              "Cross-Origin-Resource-Policy": {
                "description": "Cross-origin resource policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-site",
                    "cross-origin"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Service liveness and diagnostic snapshot.",
                  "required": [
                    "ok",
                    "time",
                    "uptime_ms",
                    "version"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "time": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "now": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "uptime_ms": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "region": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "commit": {
                      "type": "string",
                      "nullable": true
                    },
                    "sentry_env": {
                      "type": "string",
                      "nullable": true
                    },
                    "kv_namespace": {
                      "type": "string",
                      "nullable": true
                    },
                    "ua_ok": {
                      "type": "boolean"
                    },
                    "cache_conf": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "string"
                        },
                        "ttl_s": {
                          "type": "integer"
                        },
                        "negative_ttl_s": {
                          "type": "integer"
                        },
                        "kv_enabled": {
                          "type": "boolean"
                        }
                      }
                    },
                    "limits": {
                      "type": "object",
                      "description": "Per-route-family rate-limit ceiling for anonymous callers, as actually enforced by the rate-limit middleware (derived from the same policy pipeline, not a static default). Keys are route families: format, format_stream, export, format_items, audit, fallback. Windows differ per family, so each entry carries its own window_s.",
                      "additionalProperties": {
                        "type": "object",
                        "required": [
                          "limit",
                          "window_s"
                        ],
                        "properties": {
                          "limit": {
                            "type": "integer",
                            "minimum": 1
                          },
                          "window_s": {
                            "type": "integer",
                            "minimum": 1
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "time": "2026-06-04T00:00:00.000Z",
                  "uptime_ms": 12345,
                  "region": "iad1",
                  "version": "c7f9977"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                },
                "examples": {
                  "badInput": {
                    "value": {
                      "ok": false,
                      "code": "BAD_REQUEST",
                      "error": "Invalid input"
                    }
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/detect": {
      "post": {
        "tags": [
          "Resolve"
        ],
        "summary": "Detect scholarly identifiers in free-form text",
        "description": "Pure text processing. Returns every scholarly identifier found in the\nsupplied text. **No outbound network calls, no resolution, and no\nformatter pipeline** — so this route never emits `x-scholar-formatter`,\n`x-scholar-style`, or any `x-csl-*` header.\n\nResults are de-duplicated by `(type, value)` in detection order, and\n`value` is the canonical form of the token. **Zero identifiers is not an\nerror**: `count: 0` with an empty array is a valid 200.\n\n`HEAD /api/detect` returns 204 with the same rails headers and an empty\nbody.\n",
        "operationId": "detectCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 10000,
                    "description": "Free-form text to scan. Trimmed before processing, and the 10,000\ncharacter cap is applied to the trimmed value.\n"
                  }
                }
              },
              "examples": {
                "mixed": {
                  "summary": "Free text carrying two identifiers",
                  "value": {
                    "text": "See 10.1038/nature12373 and PMID: 23831765 for details."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Identifiers found in the supplied text.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Auth-Source": {
                "description": "Where the auth came from (first-party, rapidapi, anonymous).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "first-party",
                    "rapidapi",
                    "anonymous"
                  ]
                }
              },
              "X-Auth-Plan": {
                "description": "Effective plan for this request (Free/Developer/Pro/Enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "count",
                    "identifiers"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "count": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Length of `identifiers`."
                    },
                    "identifiers": {
                      "type": "array",
                      "description": "De-duplicated by `(type, value)`, in detection order.",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "type",
                          "value"
                        ],
                        "description": "One detected identifier. `raw` and `source` are present only when the\ndetector kept the original token or recorded which pass matched — do\nnot depend on either being set.\n",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "doi",
                              "pmid",
                              "pmcid",
                              "isbn",
                              "arxiv",
                              "issn",
                              "eissn",
                              "ads",
                              "url"
                            ],
                            "description": "`url` is emitted for a recognized scholarly host that is not\nalready covered by a more specific identifier.\n"
                          },
                          "value": {
                            "type": "string",
                            "description": "Canonical form of the identifier."
                          },
                          "raw": {
                            "type": "string",
                            "description": "Original token, when it differs from `value`."
                          },
                          "source": {
                            "type": "string",
                            "description": "Detector pass that matched, e.g. `detect:url`."
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "found": {
                    "summary": "Two identifiers detected",
                    "value": {
                      "ok": true,
                      "count": 2,
                      "identifiers": [
                        {
                          "type": "doi",
                          "value": "10.1038/nature12373"
                        },
                        {
                          "type": "pmid",
                          "value": "23831765"
                        }
                      ]
                    }
                  },
                  "none": {
                    "summary": "No identifiers — still a 200",
                    "value": {
                      "ok": true,
                      "count": 0,
                      "identifiers": []
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/lookup": {
      "post": {
        "tags": [
          "Resolve"
        ],
        "summary": "Resolve a single identifier to normalized metadata",
        "description": "Resolves one identifier (DOI, PMID, PMCID, ISBN, ISSN/eISSN, arXiv, ADS\nbibcode, or a scholarly URL) and returns the normalized bibliographic\nrecord. **No citation is rendered** — use `/api/format` for that.\n\nThe input is normalized before detection, so wrapped forms (a `doi.org`\nURL, a `PMID:` prefix) are accepted. Only the **first** identifier found\nis resolved; the detected type and canonical value are echoed back in\n`input`.\n\nA record that resolves nowhere is **not an error**: the response is 200\nwith `result: null` and `reason: \"not_found\"`. A 400 is returned only\nwhen the input carries no recognizable identifier at all.\n\n`HEAD /api/lookup` returns 204 with the same rails headers and an empty\nbody.\n",
        "operationId": "lookupCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "One identifier — DOI, PMID, PMCID, ISBN, ISSN/eISSN, arXiv, ADS\nbibcode, or a scholarly URL. Wrapped forms (a `doi.org` URL, a\n`PMID:` prefix) are normalized before detection. Only the first\nidentifier found is resolved.\n"
                  }
                }
              },
              "examples": {
                "doi": {
                  "summary": "Bare DOI",
                  "value": {
                    "id": "10.1056/nejmoa2033700"
                  }
                },
                "wrapped": {
                  "summary": "DOI as a doi.org URL",
                  "value": {
                    "id": "https://doi.org/10.1038/s41586-020-2649-2"
                  }
                },
                "pmid": {
                  "summary": "Prefixed PMID",
                  "value": {
                    "id": "PMID: 30049270"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resolution outcome. `result` is the normalized record, or `null`\nwith `reason: \"not_found\"` when no record was found.\n",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Auth-Source": {
                "description": "Where the auth came from (first-party, rapidapi, anonymous).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "first-party",
                    "rapidapi",
                    "anonymous"
                  ]
                }
              },
              "X-Auth-Plan": {
                "description": "Effective plan for this request (Free/Developer/Pro/Enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "input",
                    "result"
                  ],
                  "description": "`result` is `null` with `reason: \"not_found\"` when the identifier was\nrecognized but resolved to no record. That is a 200, not an error.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "input": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "type",
                        "value"
                      ],
                      "description": "The first identifier detected in the request, canonicalized.",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "doi",
                            "pmid",
                            "pmcid",
                            "isbn",
                            "arxiv",
                            "issn",
                            "eissn",
                            "ads",
                            "url"
                          ]
                        },
                        "value": {
                          "type": "string"
                        }
                      }
                    },
                    "result": {
                      "description": "The resolved record, or `null` when nothing resolved.",
                      "type": "object",
                      "allOf": [
                        {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "Compact, response-safe view of a resolved bibliographic record — the\nsame slim shape the format routes build their items from. Every field\nexcept `id` is optional, because a record carries only what its source\nsupplied.\n",
                          "required": [
                            "id"
                          ],
                          "properties": {
                            "id": {
                              "type": "string",
                              "description": "Stable item key derived from the identifiers."
                            },
                            "type": {
                              "type": "string",
                              "description": "CSL item type (e.g. `article-journal`, `book`, `chapter`, `dataset`)."
                            },
                            "title": {
                              "type": "string"
                            },
                            "authors": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "additionalProperties": true,
                                "description": "A person. Structured records carry `family`/`given`; sources that\nsupply an unsplittable name use `literal` instead.\n",
                                "properties": {
                                  "family": {
                                    "type": "string"
                                  },
                                  "given": {
                                    "type": "string"
                                  },
                                  "suffix": {
                                    "type": "string"
                                  },
                                  "literal": {
                                    "type": "string"
                                  }
                                }
                              }
                            },
                            "container": {
                              "type": "object",
                              "additionalProperties": true,
                              "description": "Journal or book the work appears in.",
                              "properties": {
                                "title": {
                                  "type": "string"
                                },
                                "abbreviated": {
                                  "type": "string"
                                },
                                "volume": {
                                  "oneOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "integer"
                                    }
                                  ]
                                },
                                "issue": {
                                  "oneOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "integer"
                                    }
                                  ]
                                },
                                "issn": {
                                  "type": "string",
                                  "description": "Print ISSN of the serial."
                                },
                                "eissn": {
                                  "type": "string",
                                  "description": "Electronic ISSN of the serial."
                                }
                              }
                            },
                            "identifiers": {
                              "type": "array",
                              "description": "Present only when the record carries at least one identifier.",
                              "items": {
                                "type": "object",
                                "additionalProperties": true,
                                "required": [
                                  "type",
                                  "value"
                                ],
                                "properties": {
                                  "type": {
                                    "type": "string"
                                  },
                                  "value": {
                                    "type": "string"
                                  }
                                }
                              }
                            },
                            "issued": {
                              "type": "object",
                              "additionalProperties": true,
                              "description": "Present only when the record carries a publication year.",
                              "properties": {
                                "year": {
                                  "type": "integer"
                                }
                              }
                            },
                            "pages": {
                              "type": "object",
                              "additionalProperties": true,
                              "description": "Present only when the record carries a first or last page.",
                              "properties": {
                                "first": {
                                  "oneOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "integer"
                                    }
                                  ]
                                },
                                "last": {
                                  "oneOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "integer"
                                    }
                                  ]
                                }
                              }
                            },
                            "number": {
                              "allOf": [
                                {
                                  "oneOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "integer"
                                    }
                                  ]
                                }
                              ],
                              "description": "Report or thesis number, where the record carries one."
                            },
                            "url": {
                              "type": "string"
                            },
                            "_source": {
                              "description": "Which upstream service supplied the record.",
                              "oneOf": [
                                {
                                  "type": "string"
                                },
                                {
                                  "type": "object",
                                  "additionalProperties": true,
                                  "properties": {
                                    "service": {
                                      "type": "string"
                                    },
                                    "requestUrl": {
                                      "type": "string"
                                    }
                                  }
                                }
                              ]
                            },
                            "_checks": {
                              "type": "object",
                              "description": "Sibling field on resolved items; populated only when ?checks= is set.",
                              "additionalProperties": false,
                              "properties": {
                                "retraction": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "properties": {
                                    "status": {
                                      "type": "string",
                                      "enum": [
                                        "ok",
                                        "retracted",
                                        "concern",
                                        "correction",
                                        "unknown"
                                      ]
                                    },
                                    "notices": {
                                      "type": "array",
                                      "items": {
                                        "type": "object",
                                        "additionalProperties": false,
                                        "properties": {
                                          "type": {
                                            "type": "string",
                                            "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                                          },
                                          "label": {
                                            "type": "string"
                                          },
                                          "doi": {
                                            "type": "string",
                                            "nullable": true
                                          },
                                          "date": {
                                            "type": "string",
                                            "nullable": true
                                          },
                                          "source": {
                                            "type": "string",
                                            "nullable": true
                                          }
                                        }
                                      }
                                    },
                                    "error": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "properties": {
                                        "code": {
                                          "type": "string"
                                        },
                                        "message": {
                                          "type": "string"
                                        }
                                      }
                                    }
                                  }
                                },
                                "open_access": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "properties": {
                                    "status": {
                                      "type": "string",
                                      "enum": [
                                        "open",
                                        "closed",
                                        "unknown"
                                      ]
                                    },
                                    "oa_status": {
                                      "type": "string",
                                      "enum": [
                                        "gold",
                                        "green",
                                        "hybrid",
                                        "bronze",
                                        "closed"
                                      ]
                                    },
                                    "best_url": {
                                      "type": "string"
                                    },
                                    "pdf_url": {
                                      "type": "string",
                                      "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                                      "nullable": true
                                    },
                                    "license": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "version": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "error": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "properties": {
                                        "code": {
                                          "type": "string"
                                        },
                                        "message": {
                                          "type": "string"
                                        }
                                      }
                                    }
                                  }
                                },
                                "doaj": {
                                  "type": "object",
                                  "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
                                  "additionalProperties": false,
                                  "properties": {
                                    "status": {
                                      "type": "string",
                                      "enum": [
                                        "indexed",
                                        "not_indexed",
                                        "unknown"
                                      ]
                                    },
                                    "in_doaj": {
                                      "type": "boolean"
                                    },
                                    "title": {
                                      "type": "string",
                                      "description": "DOAJ's journal title (match confirmation)."
                                    },
                                    "license": {
                                      "type": "string",
                                      "description": "Primary licence type, e.g. \"CC BY\"."
                                    },
                                    "issn": {
                                      "type": "string",
                                      "description": "ISSN matched on (normalised NNNN-NNNX)."
                                    },
                                    "url": {
                                      "type": "string",
                                      "description": "Canonical DOAJ table-of-contents URL for the journal."
                                    },
                                    "error": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "properties": {
                                        "code": {
                                          "type": "string"
                                        },
                                        "message": {
                                          "type": "string"
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            },
                            "_provenance": {
                              "type": "object",
                              "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
                              "additionalProperties": false,
                              "required": [
                                "transform_version",
                                "sources",
                                "resolved_at"
                              ],
                              "properties": {
                                "transform_version": {
                                  "type": "string",
                                  "description": "Pinned dep digest mirroring x-scholar-transform-version."
                                },
                                "resolved_at": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "request_id": {
                                  "type": "string",
                                  "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
                                },
                                "sources": {
                                  "type": "array",
                                  "description": "Sources that contributed the winning record (V2 emits the single winner).",
                                  "items": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "name"
                                    ],
                                    "properties": {
                                      "name": {
                                        "type": "string",
                                        "description": "Source service name (e.g., \"crossref\")"
                                      },
                                      "url": {
                                        "type": "string"
                                      },
                                      "fetched_at": {
                                        "type": "string",
                                        "format": "date-time",
                                        "description": "When this process fetched the record."
                                      },
                                      "upstream_fetched_at": {
                                        "type": "string",
                                        "format": "date-time",
                                        "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                                      },
                                      "cache": {
                                        "type": "string",
                                        "enum": [
                                          "hit",
                                          "miss",
                                          "bypass"
                                        ]
                                      },
                                      "role": {
                                        "type": "string",
                                        "enum": [
                                          "primary",
                                          "fallback"
                                        ],
                                        "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                                      },
                                      "ttl_band": {
                                        "type": "string",
                                        "enum": [
                                          "recent",
                                          "mid",
                                          "frozen"
                                        ],
                                        "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                                      }
                                    }
                                  }
                                },
                                "fallbacks_tried": {
                                  "type": "array",
                                  "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
                                  "items": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "name",
                                      "outcome"
                                    ],
                                    "properties": {
                                      "name": {
                                        "type": "string"
                                      },
                                      "outcome": {
                                        "type": "string",
                                        "enum": [
                                          "won",
                                          "not_found",
                                          "error",
                                          "empty",
                                          "skipped"
                                        ]
                                      },
                                      "reason": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                },
                                "fields_from_source": {
                                  "type": "array",
                                  "description": "CSL-relevant fields the upstream record populated.",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "fields_absent": {
                                  "type": "array",
                                  "description": "CSL-relevant fields the schema permits but upstream did not supply.",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "normalization": {
                                  "type": "array",
                                  "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
                                  "items": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "rule",
                                      "from",
                                      "to"
                                    ],
                                    "properties": {
                                      "rule": {
                                        "type": "string",
                                        "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                                      },
                                      "from": {
                                        "type": "string"
                                      },
                                      "to": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                },
                                "field_provenance": {
                                  "type": "object",
                                  "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
                                  "additionalProperties": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "source"
                                    ],
                                    "properties": {
                                      "source": {
                                        "type": "string"
                                      },
                                      "upstream_fetched_at": {
                                        "type": "string",
                                        "format": "date-time"
                                      }
                                    }
                                  }
                                },
                                "full_metadata": {
                                  "type": "object",
                                  "description": "Rich linked-data graph; present only under ?provenance=full.",
                                  "additionalProperties": false,
                                  "properties": {
                                    "funders": {
                                      "type": "array",
                                      "items": {
                                        "type": "object",
                                        "additionalProperties": false,
                                        "properties": {
                                          "name": {
                                            "type": "string"
                                          },
                                          "doi": {
                                            "type": "string"
                                          },
                                          "award": {
                                            "type": "array",
                                            "items": {
                                              "type": "string"
                                            }
                                          }
                                        }
                                      }
                                    },
                                    "orcids": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "ror_ids": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "license": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "clinical_trial_ids": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                },
                                "trust_signals": {
                                  "type": "object",
                                  "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
                                  "additionalProperties": false,
                                  "properties": {
                                    "retraction": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "required": [
                                        "requested",
                                        "evaluated"
                                      ],
                                      "properties": {
                                        "requested": {
                                          "type": "boolean"
                                        },
                                        "evaluated": {
                                          "type": "boolean"
                                        },
                                        "status": {
                                          "type": "string",
                                          "enum": [
                                            "ok",
                                            "retracted",
                                            "concern",
                                            "correction",
                                            "unknown"
                                          ]
                                        },
                                        "skipped_reason": {
                                          "type": "string",
                                          "enum": [
                                            "no_doi"
                                          ]
                                        }
                                      }
                                    },
                                    "open_access": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "required": [
                                        "requested",
                                        "evaluated"
                                      ],
                                      "properties": {
                                        "requested": {
                                          "type": "boolean"
                                        },
                                        "evaluated": {
                                          "type": "boolean"
                                        },
                                        "status": {
                                          "type": "string",
                                          "enum": [
                                            "open",
                                            "closed",
                                            "unknown"
                                          ]
                                        },
                                        "oa_status": {
                                          "type": "string",
                                          "enum": [
                                            "gold",
                                            "green",
                                            "hybrid",
                                            "bronze",
                                            "closed"
                                          ]
                                        },
                                        "pdf_url": {
                                          "type": "string",
                                          "nullable": true
                                        },
                                        "skipped_reason": {
                                          "type": "string",
                                          "enum": [
                                            "no_doi"
                                          ]
                                        }
                                      }
                                    }
                                  }
                                },
                                "mode": {
                                  "type": "string",
                                  "enum": [
                                    "strict",
                                    "best-effort"
                                  ],
                                  "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
                                },
                                "selection_reason": {
                                  "type": "string",
                                  "enum": [
                                    "static_chain_position"
                                  ],
                                  "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
                                },
                                "container_only": {
                                  "type": "boolean",
                                  "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
                                },
                                "conflicts": {
                                  "type": "object",
                                  "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
                                  "additionalProperties": false,
                                  "required": [
                                    "status"
                                  ],
                                  "properties": {
                                    "checked_against": {
                                      "type": "string",
                                      "description": "The independent source cross-checked against (omitted when none available)."
                                    },
                                    "status": {
                                      "type": "string",
                                      "enum": [
                                        "agreed",
                                        "conflict",
                                        "unavailable"
                                      ]
                                    },
                                    "skipped_reason": {
                                      "type": "string",
                                      "enum": [
                                        "no_secondary_source",
                                        "upstream_error",
                                        "not_found"
                                      ]
                                    },
                                    "fields": {
                                      "type": "array",
                                      "description": "Field-level disagreements; present only when status is `conflict`.",
                                      "items": {
                                        "type": "object",
                                        "additionalProperties": false,
                                        "required": [
                                          "field",
                                          "primary",
                                          "secondary"
                                        ],
                                        "properties": {
                                          "field": {
                                            "type": "string",
                                            "enum": [
                                              "title",
                                              "first_author",
                                              "year",
                                              "container"
                                            ]
                                          },
                                          "primary": {
                                            "type": "object",
                                            "additionalProperties": false,
                                            "required": [
                                              "source",
                                              "value"
                                            ],
                                            "properties": {
                                              "source": {
                                                "type": "string"
                                              },
                                              "value": {
                                                "oneOf": [
                                                  {
                                                    "type": "string"
                                                  },
                                                  {
                                                    "type": "number"
                                                  }
                                                ]
                                              }
                                            }
                                          },
                                          "secondary": {
                                            "type": "object",
                                            "additionalProperties": false,
                                            "required": [
                                              "source",
                                              "value"
                                            ],
                                            "properties": {
                                              "source": {
                                                "type": "string"
                                              },
                                              "value": {
                                                "oneOf": [
                                                  {
                                                    "type": "string"
                                                  },
                                                  {
                                                    "type": "number"
                                                  }
                                                ]
                                              }
                                            }
                                          },
                                          "similarity": {
                                            "type": "number",
                                            "description": "Similarity score (0–1) for fuzzy fields."
                                          }
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      ],
                      "nullable": true
                    },
                    "reason": {
                      "type": "string",
                      "enum": [
                        "not_found"
                      ],
                      "description": "Present only when `result` is `null`."
                    }
                  }
                },
                "examples": {
                  "resolved": {
                    "summary": "Resolved record",
                    "value": {
                      "ok": true,
                      "input": {
                        "type": "doi",
                        "value": "10.1056/nejmoa2033700"
                      },
                      "result": {
                        "id": "doi:10.1056/nejmoa2033700",
                        "type": "article-journal",
                        "title": "Efficacy and Safety of the mRNA-1273 SARS-CoV-2 Vaccine",
                        "authors": [
                          {
                            "family": "Baden",
                            "given": "Lindsey R."
                          },
                          {
                            "family": "El Sahly",
                            "given": "Hana M."
                          }
                        ],
                        "container": {
                          "title": "The New England Journal of Medicine",
                          "volume": "384",
                          "issue": "5",
                          "issn": "0028-4793"
                        },
                        "identifiers": [
                          {
                            "type": "doi",
                            "value": "10.1056/nejmoa2033700"
                          }
                        ],
                        "issued": {
                          "year": 2021
                        },
                        "pages": {
                          "first": "403",
                          "last": "416"
                        },
                        "_source": {
                          "service": "crossref"
                        }
                      }
                    }
                  },
                  "notFound": {
                    "summary": "Identifier recognized, but no record resolved",
                    "value": {
                      "ok": true,
                      "input": {
                        "type": "doi",
                        "value": "10.9999/does-not-exist"
                      },
                      "result": null,
                      "reason": "not_found"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/format": {
      "post": {
        "tags": [
          "Format"
        ],
        "summary": "Resolve & format identifiers (batch, non-streaming)",
        "description": "Accepts a list of identifiers or a single free-text string. Resolves to metadata, deduplicates,\nand formats citations in the requested style. Returns JSON with text or HTML output.\n\nOptional enrichment via query flags:\n- `?provenance=1` — adds `_provenance` to each item (where the metadata came from)\n- `?checks=retraction,oa` (or `?checks=1`) — adds `_checks` to each item (retraction + open-access status)\n",
        "operationId": "formatCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "description": "Optional client-chosen key for retry-safe requests on the mutating POST\nroutes. When the server has idempotency enabled, a repeated request with\nthe same key and body replays the original response verbatim (with\n`Idempotent-Replayed: true`); the same key with a different body returns\n`422`. Keys are scoped per authenticated principal (or client IP when\nanonymous), so they never collide across callers. 1–255 characters of\n`[A-Za-z0-9_.:-]`.\n",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_.:-]{1,255}$",
              "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
            }
          },
          {
            "in": "query",
            "name": "checks",
            "required": false,
            "description": "Opt-in retraction/open-access enrichment. Comma-separated tokens or `1` for all known checks.\nUnknown tokens are silently stripped. Resolved set is echoed via the `x-scholar-checks` header.\n\nTokens: `retraction`, `oa`. `1`/`true` expands to the always-available set (`retraction,oa`).\n`doaj` (DOAJ journal-indexing, ISSN-keyed) is additionally available but must be named\nexplicitly — it is gated by the server flag `ENABLE_DOAJ_CHECK` and is not part of `?checks=1`.\n",
            "schema": {
              "type": "string",
              "example": "retraction,oa"
            }
          },
          {
            "in": "query",
            "name": "provenance",
            "required": false,
            "description": "Opt-in per-item provenance manifest (`_provenance`). Set to `1`, `true`, `yes`, or `on`\nto enable the standard block; set to `full` to additionally include the large\n`full_metadata` linked-data block (funders, ORCID iDs, ROR iDs, license, trial IDs);\nset to `conflicts` to add cross-source verification (`_provenance.conflicts`), which\nalso requires the `ENABLE_PROVENANCE_CONFLICTS` server flag. Modes combine, e.g.\n`full,conflicts`. Acknowledged via the `x-scholar-provenance` response header\n(`1`, `full`, `conflicts`, or a comma-joined combination).\n",
            "schema": {
              "type": "string",
              "example": "1"
            }
          },
          {
            "in": "query",
            "name": "mode",
            "required": false,
            "description": "Resolver mode (Phase 12h). Only `strict` is supported — the fixed-order resolver chain\n(deterministic ordering within the currently-deployed `transform_version`; it is NOT a\nversion pin or a historical snapshot — see /engineering-principles \"What it does not\npromise\"). `best-effort` is reserved and not yet implemented; any value other than\n`strict` resolves to `strict`, and the `x-scholar-resolver-mode` response header then\nreports `strict` (the mode that actually ran).\n",
            "schema": {
              "type": "string",
              "enum": [
                "strict"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "description": "Batch-capable. Provide either `text` (free text containing one or more\nidentifiers, one per line) or `lines` (an array of identifiers); both\nresolve and format every identifier in a single call. Bounded by a\n128 KB request body and a maximum of 500 identifiers per request.\n",
                "oneOf": [
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "text"
                    ],
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "Free text with one or more identifiers, one per line (batch input)."
                      },
                      "style": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Citation style id — a builtin name or a CSL style id."
                      },
                      "lang": {
                        "type": "string",
                        "maxLength": 16,
                        "default": "en-US",
                        "description": "BCP-47 locale for the rendered citation."
                      },
                      "locale": {
                        "type": "string",
                        "maxLength": 16,
                        "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
                      },
                      "footnote": {
                        "type": "boolean",
                        "default": false,
                        "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
                      },
                      "output": {
                        "type": "string",
                        "enum": [
                          "text",
                          "html",
                          "json"
                        ],
                        "default": "text",
                        "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
                      },
                      "nocache": {
                        "type": "boolean",
                        "default": false,
                        "description": "Bypass the resolver cache for this request."
                      }
                    }
                  },
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "lines"
                    ],
                    "properties": {
                      "lines": {
                        "type": "array",
                        "description": "Batch input: identifiers to resolve and format, one per element.",
                        "minItems": 1,
                        "maxItems": 500,
                        "items": {
                          "type": "string"
                        }
                      },
                      "style": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Citation style id — a builtin name or a CSL style id."
                      },
                      "lang": {
                        "type": "string",
                        "maxLength": 16,
                        "default": "en-US",
                        "description": "BCP-47 locale for the rendered citation."
                      },
                      "locale": {
                        "type": "string",
                        "maxLength": 16,
                        "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
                      },
                      "footnote": {
                        "type": "boolean",
                        "default": false,
                        "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
                      },
                      "output": {
                        "type": "string",
                        "enum": [
                          "text",
                          "html",
                          "json"
                        ],
                        "default": "text",
                        "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
                      },
                      "nocache": {
                        "type": "boolean",
                        "default": false,
                        "description": "Bypass the resolver cache for this request."
                      }
                    }
                  }
                ]
              },
              "examples": {
                "linesExample": {
                  "summary": "Batch lines",
                  "value": {
                    "lines": [
                      "10.1056/nejmoa2033700",
                      "PMID: 30049270",
                      "ISBN: 9780192854087"
                    ],
                    "style": "vancouver",
                    "output": "text"
                  }
                },
                "textExample": {
                  "summary": "Single text",
                  "value": {
                    "text": "10.1056/nejmoa2033700",
                    "style": "vancouver",
                    "output": "text"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Auth-Source": {
                "description": "Where the auth came from (first-party, rapidapi, anonymous).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "first-party",
                    "rapidapi",
                    "anonymous"
                  ]
                }
              },
              "X-Auth-Plan": {
                "description": "Effective plan for this request (Free/Developer/Pro/Enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Checks": {
                "description": "Echo of the resolved enrichment checks (e.g. \"retraction,oa\") when ?checks= is honored.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Provenance": {
                "description": "Set to \"1\" when ?provenance=1 is honored; \"full\" when ?provenance=full is honored.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "1",
                    "full"
                  ]
                }
              },
              "X-Scholar-Resolver-Mode": {
                "description": "Resolver mode applied (currently always \"strict\"); set only when ?mode= is supplied.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "strict"
                  ]
                }
              },
              "X-Scholar-Transform-Version": {
                "description": "Public, monotonically-versioned tag for normalisation + formatting\nlogic — returned on every response. Serves as the active API version\nunder the header-based versioning scheme.\n",
                "schema": {
                  "type": "string",
                  "example": "2026-08-18"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to \"true\" when this response was replayed from a prior request with\nthe same `Idempotency-Key` (not freshly computed).\n",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Deprecation": {
                "description": "Present only on responses from a deprecated API version. Signals that\nthe version is deprecated (per the deprecation policy in the API\noverview); pair with `Sunset` for the retirement date.\n",
                "schema": {
                  "type": "string"
                }
              },
              "Sunset": {
                "description": "Present only on deprecated API versions. RFC 8594 HTTP-date after which\nthe version is retired (minimum 180 days after the `Deprecation` notice).\n",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              },
              "Content-Security-Policy": {
                "description": "CSP controlling resource loading.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Content-Type-Options": {
                "description": "MIME type sniffing prevention.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "nosniff"
                  ]
                }
              },
              "X-Frame-Options": {
                "description": "Clickjacking protection.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "DENY",
                    "SAMEORIGIN"
                  ]
                }
              },
              "Referrer-Policy": {
                "description": "Referrer information policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-referrer",
                    "no-referrer-when-downgrade",
                    "origin",
                    "origin-when-cross-origin",
                    "same-origin",
                    "strict-origin",
                    "strict-origin-when-cross-origin",
                    "unsafe-url"
                  ]
                }
              },
              "Permissions-Policy": {
                "description": "Feature policy controls.",
                "schema": {
                  "type": "string"
                }
              },
              "Cross-Origin-Opener-Policy": {
                "description": "Cross-origin opener policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-origin-allow-popups",
                    "unsafe-none"
                  ]
                }
              },
              "Cross-Origin-Resource-Policy": {
                "description": "Cross-origin resource policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-site",
                    "cross-origin"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Successful format response. `items[]` is always populated by /api/format and\nis populated by /api/format-items only when `?checks=` or `?provenance=1` is set.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "formatter": {
                      "type": "string",
                      "enum": [
                        "builtin",
                        "csl"
                      ]
                    },
                    "styleRequested": {
                      "type": "string",
                      "nullable": true
                    },
                    "styleUsed": {
                      "type": "string"
                    },
                    "lang": {
                      "type": "string"
                    },
                    "footnote": {
                      "type": "boolean"
                    },
                    "outputMode": {
                      "type": "string",
                      "enum": [
                        "text",
                        "html",
                        "json"
                      ]
                    },
                    "itemsIn": {
                      "type": "integer"
                    },
                    "itemsOut": {
                      "type": "integer"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "description": "Slim bibliographic item view. Carries optional `_checks` and `_provenance`\nsibling fragments when the corresponding query flags are set on the request.\n",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "idx": {
                            "type": "integer",
                            "description": "First contributing input index."
                          },
                          "sourceIdxs": {
                            "type": "array",
                            "items": {
                              "type": "integer"
                            }
                          },
                          "_checks": {
                            "type": "object",
                            "description": "Sibling field on resolved items; populated only when ?checks= is set.",
                            "additionalProperties": false,
                            "properties": {
                              "retraction": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "ok",
                                      "retracted",
                                      "concern",
                                      "correction",
                                      "unknown"
                                    ]
                                  },
                                  "notices": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "properties": {
                                        "type": {
                                          "type": "string",
                                          "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                                        },
                                        "label": {
                                          "type": "string"
                                        },
                                        "doi": {
                                          "type": "string",
                                          "nullable": true
                                        },
                                        "date": {
                                          "type": "string",
                                          "nullable": true
                                        },
                                        "source": {
                                          "type": "string",
                                          "nullable": true
                                        }
                                      }
                                    }
                                  },
                                  "error": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "properties": {
                                      "code": {
                                        "type": "string"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "open_access": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "open",
                                      "closed",
                                      "unknown"
                                    ]
                                  },
                                  "oa_status": {
                                    "type": "string",
                                    "enum": [
                                      "gold",
                                      "green",
                                      "hybrid",
                                      "bronze",
                                      "closed"
                                    ]
                                  },
                                  "best_url": {
                                    "type": "string"
                                  },
                                  "pdf_url": {
                                    "type": "string",
                                    "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                                    "nullable": true
                                  },
                                  "license": {
                                    "type": "string",
                                    "nullable": true
                                  },
                                  "version": {
                                    "type": "string",
                                    "nullable": true
                                  },
                                  "error": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "properties": {
                                      "code": {
                                        "type": "string"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "doaj": {
                                "type": "object",
                                "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
                                "additionalProperties": false,
                                "properties": {
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "indexed",
                                      "not_indexed",
                                      "unknown"
                                    ]
                                  },
                                  "in_doaj": {
                                    "type": "boolean"
                                  },
                                  "title": {
                                    "type": "string",
                                    "description": "DOAJ's journal title (match confirmation)."
                                  },
                                  "license": {
                                    "type": "string",
                                    "description": "Primary licence type, e.g. \"CC BY\"."
                                  },
                                  "issn": {
                                    "type": "string",
                                    "description": "ISSN matched on (normalised NNNN-NNNX)."
                                  },
                                  "url": {
                                    "type": "string",
                                    "description": "Canonical DOAJ table-of-contents URL for the journal."
                                  },
                                  "error": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "properties": {
                                      "code": {
                                        "type": "string"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "_provenance": {
                            "type": "object",
                            "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
                            "additionalProperties": false,
                            "required": [
                              "transform_version",
                              "sources",
                              "resolved_at"
                            ],
                            "properties": {
                              "transform_version": {
                                "type": "string",
                                "description": "Pinned dep digest mirroring x-scholar-transform-version."
                              },
                              "resolved_at": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "request_id": {
                                "type": "string",
                                "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
                              },
                              "sources": {
                                "type": "array",
                                "description": "Sources that contributed the winning record (V2 emits the single winner).",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "name"
                                  ],
                                  "properties": {
                                    "name": {
                                      "type": "string",
                                      "description": "Source service name (e.g., \"crossref\")"
                                    },
                                    "url": {
                                      "type": "string"
                                    },
                                    "fetched_at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When this process fetched the record."
                                    },
                                    "upstream_fetched_at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                                    },
                                    "cache": {
                                      "type": "string",
                                      "enum": [
                                        "hit",
                                        "miss",
                                        "bypass"
                                      ]
                                    },
                                    "role": {
                                      "type": "string",
                                      "enum": [
                                        "primary",
                                        "fallback"
                                      ],
                                      "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                                    },
                                    "ttl_band": {
                                      "type": "string",
                                      "enum": [
                                        "recent",
                                        "mid",
                                        "frozen"
                                      ],
                                      "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                                    }
                                  }
                                }
                              },
                              "fallbacks_tried": {
                                "type": "array",
                                "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "name",
                                    "outcome"
                                  ],
                                  "properties": {
                                    "name": {
                                      "type": "string"
                                    },
                                    "outcome": {
                                      "type": "string",
                                      "enum": [
                                        "won",
                                        "not_found",
                                        "error",
                                        "empty",
                                        "skipped"
                                      ]
                                    },
                                    "reason": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "fields_from_source": {
                                "type": "array",
                                "description": "CSL-relevant fields the upstream record populated.",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "fields_absent": {
                                "type": "array",
                                "description": "CSL-relevant fields the schema permits but upstream did not supply.",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "normalization": {
                                "type": "array",
                                "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "rule",
                                    "from",
                                    "to"
                                  ],
                                  "properties": {
                                    "rule": {
                                      "type": "string",
                                      "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                                    },
                                    "from": {
                                      "type": "string"
                                    },
                                    "to": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "field_provenance": {
                                "type": "object",
                                "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
                                "additionalProperties": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "source"
                                  ],
                                  "properties": {
                                    "source": {
                                      "type": "string"
                                    },
                                    "upstream_fetched_at": {
                                      "type": "string",
                                      "format": "date-time"
                                    }
                                  }
                                }
                              },
                              "full_metadata": {
                                "type": "object",
                                "description": "Rich linked-data graph; present only under ?provenance=full.",
                                "additionalProperties": false,
                                "properties": {
                                  "funders": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "properties": {
                                        "name": {
                                          "type": "string"
                                        },
                                        "doi": {
                                          "type": "string"
                                        },
                                        "award": {
                                          "type": "array",
                                          "items": {
                                            "type": "string"
                                          }
                                        }
                                      }
                                    }
                                  },
                                  "orcids": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  },
                                  "ror_ids": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  },
                                  "license": {
                                    "type": "string",
                                    "nullable": true
                                  },
                                  "clinical_trial_ids": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "trust_signals": {
                                "type": "object",
                                "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
                                "additionalProperties": false,
                                "properties": {
                                  "retraction": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "requested",
                                      "evaluated"
                                    ],
                                    "properties": {
                                      "requested": {
                                        "type": "boolean"
                                      },
                                      "evaluated": {
                                        "type": "boolean"
                                      },
                                      "status": {
                                        "type": "string",
                                        "enum": [
                                          "ok",
                                          "retracted",
                                          "concern",
                                          "correction",
                                          "unknown"
                                        ]
                                      },
                                      "skipped_reason": {
                                        "type": "string",
                                        "enum": [
                                          "no_doi"
                                        ]
                                      }
                                    }
                                  },
                                  "open_access": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "requested",
                                      "evaluated"
                                    ],
                                    "properties": {
                                      "requested": {
                                        "type": "boolean"
                                      },
                                      "evaluated": {
                                        "type": "boolean"
                                      },
                                      "status": {
                                        "type": "string",
                                        "enum": [
                                          "open",
                                          "closed",
                                          "unknown"
                                        ]
                                      },
                                      "oa_status": {
                                        "type": "string",
                                        "enum": [
                                          "gold",
                                          "green",
                                          "hybrid",
                                          "bronze",
                                          "closed"
                                        ]
                                      },
                                      "pdf_url": {
                                        "type": "string",
                                        "nullable": true
                                      },
                                      "skipped_reason": {
                                        "type": "string",
                                        "enum": [
                                          "no_doi"
                                        ]
                                      }
                                    }
                                  }
                                }
                              },
                              "mode": {
                                "type": "string",
                                "enum": [
                                  "strict",
                                  "best-effort"
                                ],
                                "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
                              },
                              "selection_reason": {
                                "type": "string",
                                "enum": [
                                  "static_chain_position"
                                ],
                                "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
                              },
                              "container_only": {
                                "type": "boolean",
                                "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
                              },
                              "conflicts": {
                                "type": "object",
                                "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
                                "additionalProperties": false,
                                "required": [
                                  "status"
                                ],
                                "properties": {
                                  "checked_against": {
                                    "type": "string",
                                    "description": "The independent source cross-checked against (omitted when none available)."
                                  },
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "agreed",
                                      "conflict",
                                      "unavailable"
                                    ]
                                  },
                                  "skipped_reason": {
                                    "type": "string",
                                    "enum": [
                                      "no_secondary_source",
                                      "upstream_error",
                                      "not_found"
                                    ]
                                  },
                                  "fields": {
                                    "type": "array",
                                    "description": "Field-level disagreements; present only when status is `conflict`.",
                                    "items": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "required": [
                                        "field",
                                        "primary",
                                        "secondary"
                                      ],
                                      "properties": {
                                        "field": {
                                          "type": "string",
                                          "enum": [
                                            "title",
                                            "first_author",
                                            "year",
                                            "container"
                                          ]
                                        },
                                        "primary": {
                                          "type": "object",
                                          "additionalProperties": false,
                                          "required": [
                                            "source",
                                            "value"
                                          ],
                                          "properties": {
                                            "source": {
                                              "type": "string"
                                            },
                                            "value": {
                                              "oneOf": [
                                                {
                                                  "type": "string"
                                                },
                                                {
                                                  "type": "number"
                                                }
                                              ]
                                            }
                                          }
                                        },
                                        "secondary": {
                                          "type": "object",
                                          "additionalProperties": false,
                                          "required": [
                                            "source",
                                            "value"
                                          ],
                                          "properties": {
                                            "source": {
                                              "type": "string"
                                            },
                                            "value": {
                                              "oneOf": [
                                                {
                                                  "type": "string"
                                                },
                                                {
                                                  "type": "number"
                                                }
                                              ]
                                            }
                                          }
                                        },
                                        "similarity": {
                                          "type": "number",
                                          "description": "Similarity score (0–1) for fuzzy fields."
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "text": {
                      "type": "string",
                      "description": "Plain-text rendered citation(s)."
                    },
                    "html": {
                      "type": "string",
                      "description": "HTML rendered citation(s)."
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Phase 12b batch summary. Aggregate counts + a duplicate-group list for a\nrequest. Additive metadata only — it never changes the formatted output.\n`resolved` counts input lines that mapped to a work, so the buckets are\nself-consistent: `linesIn === resolved + notFound + errored + skipped`,\nand `duplicates === resolved - afterDedupe`. The same shape appears on the\nstream `done` frame. Error/skip buckets are best-effort and may differ\nslightly between /api/format (dedups failing lines) and\n/api/format/stream (counts them per occurrence).\n",
                      "properties": {
                        "linesIn": {
                          "type": "integer",
                          "description": "Total input lines."
                        },
                        "resolved": {
                          "type": "integer",
                          "description": "Input lines that resolved to a work."
                        },
                        "afterDedupe": {
                          "type": "integer",
                          "description": "Distinct works after de-duplication."
                        },
                        "duplicates": {
                          "type": "integer",
                          "description": "Collapsed duplicate lines (resolved - afterDedupe)."
                        },
                        "notFound": {
                          "type": "integer",
                          "description": "Lines that resolved to no record."
                        },
                        "errored": {
                          "type": "integer",
                          "description": "Lines that failed on an upstream/other error."
                        },
                        "skipped": {
                          "type": "integer",
                          "description": "ISSN-container / ADS-without-token lines skipped."
                        },
                        "warned": {
                          "type": "integer",
                          "description": "Count of batch warning strings."
                        },
                        "duplicateGroups": {
                          "type": "array",
                          "description": "One entry per item whose input lines collapsed (>1 source line).",
                          "items": {
                            "type": "object",
                            "properties": {
                              "idx": {
                                "type": "integer",
                                "description": "First contributing input-line index."
                              },
                              "sourceIdxs": {
                                "type": "array",
                                "items": {
                                  "type": "integer"
                                },
                                "description": "All input-line indices that collapsed into this item."
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "formatter": "builtin",
                  "styleRequested": "vancouver",
                  "styleUsed": "vancouver",
                  "lang": "en-US",
                  "footnote": false,
                  "outputMode": "text",
                  "itemsIn": 1,
                  "itemsOut": 1,
                  "text": "Baden LR, El Sahly HM, Essink B, et al. Efficacy and Safety of the mRNA-1273 SARS-CoV-2 Vaccine. N Engl J Med. 2021;384(5):403-416.",
                  "warnings": [],
                  "meta": {
                    "linesIn": 1,
                    "resolved": 1,
                    "afterDedupe": 1,
                    "duplicates": 0,
                    "notFound": 0,
                    "errored": 0,
                    "skipped": 0,
                    "warned": 0,
                    "duplicateGroups": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/format-items": {
      "post": {
        "tags": [
          "Format"
        ],
        "summary": "Format pre-parsed items (batch, CSL-JSON input)",
        "description": "Accepts pre-parsed items in CSL-JSON form (e.g., results from a prior resolve step)\nand formats citations without re-resolving identifiers.\n\nOptional enrichment via query flags:\n- `?provenance=1` — adds `_provenance` to each item\n- `?checks=retraction,oa` (or `?checks=1`) — adds `_checks` to each item\n\nWhen either flag is set, the response also includes an `items[]` array with the slim items\n(alongside the formatted `output` string).\n",
        "operationId": "formatItemsCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "description": "Optional client-chosen key for retry-safe requests on the mutating POST\nroutes. When the server has idempotency enabled, a repeated request with\nthe same key and body replays the original response verbatim (with\n`Idempotent-Replayed: true`); the same key with a different body returns\n`422`. Keys are scoped per authenticated principal (or client IP when\nanonymous), so they never collide across callers. 1–255 characters of\n`[A-Za-z0-9_.:-]`.\n",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_.:-]{1,255}$",
              "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
            }
          },
          {
            "in": "query",
            "name": "checks",
            "required": false,
            "description": "Opt-in retraction/open-access enrichment. Comma-separated tokens or `1` for all known checks.\nUnknown tokens are silently stripped. Resolved set is echoed via the `x-scholar-checks` header.\n\nTokens: `retraction`, `oa`. `1`/`true` expands to the always-available set (`retraction,oa`).\n`doaj` (DOAJ journal-indexing, ISSN-keyed) is additionally available but must be named\nexplicitly — it is gated by the server flag `ENABLE_DOAJ_CHECK` and is not part of `?checks=1`.\n",
            "schema": {
              "type": "string",
              "example": "retraction,oa"
            }
          },
          {
            "in": "query",
            "name": "provenance",
            "required": false,
            "description": "Opt-in per-item provenance manifest (`_provenance`). Set to `1`, `true`, `yes`, or `on`\nto enable the standard block; set to `full` to additionally include the large\n`full_metadata` linked-data block (funders, ORCID iDs, ROR iDs, license, trial IDs);\nset to `conflicts` to add cross-source verification (`_provenance.conflicts`), which\nalso requires the `ENABLE_PROVENANCE_CONFLICTS` server flag. Modes combine, e.g.\n`full,conflicts`. Acknowledged via the `x-scholar-provenance` response header\n(`1`, `full`, `conflicts`, or a comma-joined combination).\n",
            "schema": {
              "type": "string",
              "example": "1"
            }
          },
          {
            "in": "query",
            "name": "mode",
            "required": false,
            "description": "Resolver mode (Phase 12h). Only `strict` is supported — the fixed-order resolver chain\n(deterministic ordering within the currently-deployed `transform_version`; it is NOT a\nversion pin or a historical snapshot — see /engineering-principles \"What it does not\npromise\"). `best-effort` is reserved and not yet implemented; any value other than\n`strict` resolves to `strict`, and the `x-scholar-resolver-mode` response header then\nreports `strict` (the mode that actually ran).\n",
            "schema": {
              "type": "string",
              "enum": [
                "strict"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "items"
                ],
                "description": "Batch-capable: formats up to 500 pre-parsed CSL-JSON items in one call.\n",
                "properties": {
                  "items": {
                    "type": "array",
                    "description": "Batch input: pre-parsed CSL-JSON items, one per element.",
                    "minItems": 1,
                    "maxItems": 500,
                    "items": {
                      "type": "object",
                      "description": "CSL-JSON item"
                    }
                  },
                  "style": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Citation style id — a builtin name or a CSL style id."
                  },
                  "lang": {
                    "type": "string",
                    "maxLength": 16,
                    "default": "en-US",
                    "description": "BCP-47 locale for the rendered citation."
                  },
                  "locale": {
                    "type": "string",
                    "maxLength": 16,
                    "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
                  },
                  "footnote": {
                    "type": "boolean",
                    "default": false,
                    "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
                  },
                  "output": {
                    "type": "string",
                    "enum": [
                      "text",
                      "html",
                      "json"
                    ],
                    "default": "text",
                    "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
                  },
                  "nocache": {
                    "type": "boolean",
                    "default": false,
                    "description": "Bypass the resolver cache for this request."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Auth-Source": {
                "description": "Where the auth came from (first-party, rapidapi, anonymous).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "first-party",
                    "rapidapi",
                    "anonymous"
                  ]
                }
              },
              "X-Auth-Plan": {
                "description": "Effective plan for this request (Free/Developer/Pro/Enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Checks": {
                "description": "Echo of the resolved enrichment checks (e.g. \"retraction,oa\") when ?checks= is honored.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Provenance": {
                "description": "Set to \"1\" when ?provenance=1 is honored; \"full\" when ?provenance=full is honored.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "1",
                    "full"
                  ]
                }
              },
              "X-Scholar-Resolver-Mode": {
                "description": "Resolver mode applied (currently always \"strict\"); set only when ?mode= is supplied.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "strict"
                  ]
                }
              },
              "X-Scholar-Transform-Version": {
                "description": "Public, monotonically-versioned tag for normalisation + formatting\nlogic — returned on every response. Serves as the active API version\nunder the header-based versioning scheme.\n",
                "schema": {
                  "type": "string",
                  "example": "2026-08-18"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to \"true\" when this response was replayed from a prior request with\nthe same `Idempotency-Key` (not freshly computed).\n",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Deprecation": {
                "description": "Present only on responses from a deprecated API version. Signals that\nthe version is deprecated (per the deprecation policy in the API\noverview); pair with `Sunset` for the retirement date.\n",
                "schema": {
                  "type": "string"
                }
              },
              "Sunset": {
                "description": "Present only on deprecated API versions. RFC 8594 HTTP-date after which\nthe version is retired (minimum 180 days after the `Deprecation` notice).\n",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              },
              "Content-Security-Policy": {
                "description": "CSP controlling resource loading.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Content-Type-Options": {
                "description": "MIME type sniffing prevention.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "nosniff"
                  ]
                }
              },
              "X-Frame-Options": {
                "description": "Clickjacking protection.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "DENY",
                    "SAMEORIGIN"
                  ]
                }
              },
              "Referrer-Policy": {
                "description": "Referrer information policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-referrer",
                    "no-referrer-when-downgrade",
                    "origin",
                    "origin-when-cross-origin",
                    "same-origin",
                    "strict-origin",
                    "strict-origin-when-cross-origin",
                    "unsafe-url"
                  ]
                }
              },
              "Permissions-Policy": {
                "description": "Feature policy controls.",
                "schema": {
                  "type": "string"
                }
              },
              "Cross-Origin-Opener-Policy": {
                "description": "Cross-origin opener policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-origin-allow-popups",
                    "unsafe-none"
                  ]
                }
              },
              "Cross-Origin-Resource-Policy": {
                "description": "Cross-origin resource policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-site",
                    "cross-origin"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Successful format response. `items[]` is always populated by /api/format and\nis populated by /api/format-items only when `?checks=` or `?provenance=1` is set.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "formatter": {
                      "type": "string",
                      "enum": [
                        "builtin",
                        "csl"
                      ]
                    },
                    "styleRequested": {
                      "type": "string",
                      "nullable": true
                    },
                    "styleUsed": {
                      "type": "string"
                    },
                    "lang": {
                      "type": "string"
                    },
                    "footnote": {
                      "type": "boolean"
                    },
                    "outputMode": {
                      "type": "string",
                      "enum": [
                        "text",
                        "html",
                        "json"
                      ]
                    },
                    "itemsIn": {
                      "type": "integer"
                    },
                    "itemsOut": {
                      "type": "integer"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "description": "Slim bibliographic item view. Carries optional `_checks` and `_provenance`\nsibling fragments when the corresponding query flags are set on the request.\n",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "idx": {
                            "type": "integer",
                            "description": "First contributing input index."
                          },
                          "sourceIdxs": {
                            "type": "array",
                            "items": {
                              "type": "integer"
                            }
                          },
                          "_checks": {
                            "type": "object",
                            "description": "Sibling field on resolved items; populated only when ?checks= is set.",
                            "additionalProperties": false,
                            "properties": {
                              "retraction": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "ok",
                                      "retracted",
                                      "concern",
                                      "correction",
                                      "unknown"
                                    ]
                                  },
                                  "notices": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "properties": {
                                        "type": {
                                          "type": "string",
                                          "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                                        },
                                        "label": {
                                          "type": "string"
                                        },
                                        "doi": {
                                          "type": "string",
                                          "nullable": true
                                        },
                                        "date": {
                                          "type": "string",
                                          "nullable": true
                                        },
                                        "source": {
                                          "type": "string",
                                          "nullable": true
                                        }
                                      }
                                    }
                                  },
                                  "error": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "properties": {
                                      "code": {
                                        "type": "string"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "open_access": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "open",
                                      "closed",
                                      "unknown"
                                    ]
                                  },
                                  "oa_status": {
                                    "type": "string",
                                    "enum": [
                                      "gold",
                                      "green",
                                      "hybrid",
                                      "bronze",
                                      "closed"
                                    ]
                                  },
                                  "best_url": {
                                    "type": "string"
                                  },
                                  "pdf_url": {
                                    "type": "string",
                                    "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                                    "nullable": true
                                  },
                                  "license": {
                                    "type": "string",
                                    "nullable": true
                                  },
                                  "version": {
                                    "type": "string",
                                    "nullable": true
                                  },
                                  "error": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "properties": {
                                      "code": {
                                        "type": "string"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "doaj": {
                                "type": "object",
                                "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
                                "additionalProperties": false,
                                "properties": {
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "indexed",
                                      "not_indexed",
                                      "unknown"
                                    ]
                                  },
                                  "in_doaj": {
                                    "type": "boolean"
                                  },
                                  "title": {
                                    "type": "string",
                                    "description": "DOAJ's journal title (match confirmation)."
                                  },
                                  "license": {
                                    "type": "string",
                                    "description": "Primary licence type, e.g. \"CC BY\"."
                                  },
                                  "issn": {
                                    "type": "string",
                                    "description": "ISSN matched on (normalised NNNN-NNNX)."
                                  },
                                  "url": {
                                    "type": "string",
                                    "description": "Canonical DOAJ table-of-contents URL for the journal."
                                  },
                                  "error": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "properties": {
                                      "code": {
                                        "type": "string"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "_provenance": {
                            "type": "object",
                            "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
                            "additionalProperties": false,
                            "required": [
                              "transform_version",
                              "sources",
                              "resolved_at"
                            ],
                            "properties": {
                              "transform_version": {
                                "type": "string",
                                "description": "Pinned dep digest mirroring x-scholar-transform-version."
                              },
                              "resolved_at": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "request_id": {
                                "type": "string",
                                "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
                              },
                              "sources": {
                                "type": "array",
                                "description": "Sources that contributed the winning record (V2 emits the single winner).",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "name"
                                  ],
                                  "properties": {
                                    "name": {
                                      "type": "string",
                                      "description": "Source service name (e.g., \"crossref\")"
                                    },
                                    "url": {
                                      "type": "string"
                                    },
                                    "fetched_at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When this process fetched the record."
                                    },
                                    "upstream_fetched_at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                                    },
                                    "cache": {
                                      "type": "string",
                                      "enum": [
                                        "hit",
                                        "miss",
                                        "bypass"
                                      ]
                                    },
                                    "role": {
                                      "type": "string",
                                      "enum": [
                                        "primary",
                                        "fallback"
                                      ],
                                      "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                                    },
                                    "ttl_band": {
                                      "type": "string",
                                      "enum": [
                                        "recent",
                                        "mid",
                                        "frozen"
                                      ],
                                      "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                                    }
                                  }
                                }
                              },
                              "fallbacks_tried": {
                                "type": "array",
                                "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "name",
                                    "outcome"
                                  ],
                                  "properties": {
                                    "name": {
                                      "type": "string"
                                    },
                                    "outcome": {
                                      "type": "string",
                                      "enum": [
                                        "won",
                                        "not_found",
                                        "error",
                                        "empty",
                                        "skipped"
                                      ]
                                    },
                                    "reason": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "fields_from_source": {
                                "type": "array",
                                "description": "CSL-relevant fields the upstream record populated.",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "fields_absent": {
                                "type": "array",
                                "description": "CSL-relevant fields the schema permits but upstream did not supply.",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "normalization": {
                                "type": "array",
                                "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "rule",
                                    "from",
                                    "to"
                                  ],
                                  "properties": {
                                    "rule": {
                                      "type": "string",
                                      "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                                    },
                                    "from": {
                                      "type": "string"
                                    },
                                    "to": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "field_provenance": {
                                "type": "object",
                                "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
                                "additionalProperties": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "source"
                                  ],
                                  "properties": {
                                    "source": {
                                      "type": "string"
                                    },
                                    "upstream_fetched_at": {
                                      "type": "string",
                                      "format": "date-time"
                                    }
                                  }
                                }
                              },
                              "full_metadata": {
                                "type": "object",
                                "description": "Rich linked-data graph; present only under ?provenance=full.",
                                "additionalProperties": false,
                                "properties": {
                                  "funders": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "properties": {
                                        "name": {
                                          "type": "string"
                                        },
                                        "doi": {
                                          "type": "string"
                                        },
                                        "award": {
                                          "type": "array",
                                          "items": {
                                            "type": "string"
                                          }
                                        }
                                      }
                                    }
                                  },
                                  "orcids": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  },
                                  "ror_ids": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  },
                                  "license": {
                                    "type": "string",
                                    "nullable": true
                                  },
                                  "clinical_trial_ids": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "trust_signals": {
                                "type": "object",
                                "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
                                "additionalProperties": false,
                                "properties": {
                                  "retraction": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "requested",
                                      "evaluated"
                                    ],
                                    "properties": {
                                      "requested": {
                                        "type": "boolean"
                                      },
                                      "evaluated": {
                                        "type": "boolean"
                                      },
                                      "status": {
                                        "type": "string",
                                        "enum": [
                                          "ok",
                                          "retracted",
                                          "concern",
                                          "correction",
                                          "unknown"
                                        ]
                                      },
                                      "skipped_reason": {
                                        "type": "string",
                                        "enum": [
                                          "no_doi"
                                        ]
                                      }
                                    }
                                  },
                                  "open_access": {
                                    "type": "object",
                                    "additionalProperties": false,
                                    "required": [
                                      "requested",
                                      "evaluated"
                                    ],
                                    "properties": {
                                      "requested": {
                                        "type": "boolean"
                                      },
                                      "evaluated": {
                                        "type": "boolean"
                                      },
                                      "status": {
                                        "type": "string",
                                        "enum": [
                                          "open",
                                          "closed",
                                          "unknown"
                                        ]
                                      },
                                      "oa_status": {
                                        "type": "string",
                                        "enum": [
                                          "gold",
                                          "green",
                                          "hybrid",
                                          "bronze",
                                          "closed"
                                        ]
                                      },
                                      "pdf_url": {
                                        "type": "string",
                                        "nullable": true
                                      },
                                      "skipped_reason": {
                                        "type": "string",
                                        "enum": [
                                          "no_doi"
                                        ]
                                      }
                                    }
                                  }
                                }
                              },
                              "mode": {
                                "type": "string",
                                "enum": [
                                  "strict",
                                  "best-effort"
                                ],
                                "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
                              },
                              "selection_reason": {
                                "type": "string",
                                "enum": [
                                  "static_chain_position"
                                ],
                                "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
                              },
                              "container_only": {
                                "type": "boolean",
                                "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
                              },
                              "conflicts": {
                                "type": "object",
                                "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
                                "additionalProperties": false,
                                "required": [
                                  "status"
                                ],
                                "properties": {
                                  "checked_against": {
                                    "type": "string",
                                    "description": "The independent source cross-checked against (omitted when none available)."
                                  },
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "agreed",
                                      "conflict",
                                      "unavailable"
                                    ]
                                  },
                                  "skipped_reason": {
                                    "type": "string",
                                    "enum": [
                                      "no_secondary_source",
                                      "upstream_error",
                                      "not_found"
                                    ]
                                  },
                                  "fields": {
                                    "type": "array",
                                    "description": "Field-level disagreements; present only when status is `conflict`.",
                                    "items": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "required": [
                                        "field",
                                        "primary",
                                        "secondary"
                                      ],
                                      "properties": {
                                        "field": {
                                          "type": "string",
                                          "enum": [
                                            "title",
                                            "first_author",
                                            "year",
                                            "container"
                                          ]
                                        },
                                        "primary": {
                                          "type": "object",
                                          "additionalProperties": false,
                                          "required": [
                                            "source",
                                            "value"
                                          ],
                                          "properties": {
                                            "source": {
                                              "type": "string"
                                            },
                                            "value": {
                                              "oneOf": [
                                                {
                                                  "type": "string"
                                                },
                                                {
                                                  "type": "number"
                                                }
                                              ]
                                            }
                                          }
                                        },
                                        "secondary": {
                                          "type": "object",
                                          "additionalProperties": false,
                                          "required": [
                                            "source",
                                            "value"
                                          ],
                                          "properties": {
                                            "source": {
                                              "type": "string"
                                            },
                                            "value": {
                                              "oneOf": [
                                                {
                                                  "type": "string"
                                                },
                                                {
                                                  "type": "number"
                                                }
                                              ]
                                            }
                                          }
                                        },
                                        "similarity": {
                                          "type": "number",
                                          "description": "Similarity score (0–1) for fuzzy fields."
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "text": {
                      "type": "string",
                      "description": "Plain-text rendered citation(s)."
                    },
                    "html": {
                      "type": "string",
                      "description": "HTML rendered citation(s)."
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Phase 12b batch summary. Aggregate counts + a duplicate-group list for a\nrequest. Additive metadata only — it never changes the formatted output.\n`resolved` counts input lines that mapped to a work, so the buckets are\nself-consistent: `linesIn === resolved + notFound + errored + skipped`,\nand `duplicates === resolved - afterDedupe`. The same shape appears on the\nstream `done` frame. Error/skip buckets are best-effort and may differ\nslightly between /api/format (dedups failing lines) and\n/api/format/stream (counts them per occurrence).\n",
                      "properties": {
                        "linesIn": {
                          "type": "integer",
                          "description": "Total input lines."
                        },
                        "resolved": {
                          "type": "integer",
                          "description": "Input lines that resolved to a work."
                        },
                        "afterDedupe": {
                          "type": "integer",
                          "description": "Distinct works after de-duplication."
                        },
                        "duplicates": {
                          "type": "integer",
                          "description": "Collapsed duplicate lines (resolved - afterDedupe)."
                        },
                        "notFound": {
                          "type": "integer",
                          "description": "Lines that resolved to no record."
                        },
                        "errored": {
                          "type": "integer",
                          "description": "Lines that failed on an upstream/other error."
                        },
                        "skipped": {
                          "type": "integer",
                          "description": "ISSN-container / ADS-without-token lines skipped."
                        },
                        "warned": {
                          "type": "integer",
                          "description": "Count of batch warning strings."
                        },
                        "duplicateGroups": {
                          "type": "array",
                          "description": "One entry per item whose input lines collapsed (>1 source line).",
                          "items": {
                            "type": "object",
                            "properties": {
                              "idx": {
                                "type": "integer",
                                "description": "First contributing input-line index."
                              },
                              "sourceIdxs": {
                                "type": "array",
                                "items": {
                                  "type": "integer"
                                },
                                "description": "All input-line indices that collapsed into this item."
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "formatter": "builtin",
                  "styleRequested": "vancouver",
                  "styleUsed": "vancouver",
                  "lang": "en-US",
                  "footnote": false,
                  "outputMode": "text",
                  "itemsIn": 1,
                  "itemsOut": 1,
                  "text": "Baden LR, El Sahly HM, Essink B, et al. Efficacy and Safety of the mRNA-1273 SARS-CoV-2 Vaccine. N Engl J Med. 2021;384(5):403-416.",
                  "warnings": [],
                  "meta": {
                    "linesIn": 1,
                    "resolved": 1,
                    "afterDedupe": 1,
                    "duplicates": 0,
                    "notFound": 0,
                    "errored": 0,
                    "skipped": 0,
                    "warned": 0,
                    "duplicateGroups": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/format/stream": {
      "post": {
        "tags": [
          "Format"
        ],
        "summary": "Resolve & format identifiers (batch, NDJSON stream)",
        "description": "Streams incremental formatting output as **newline-delimited JSON**\n(`application/x-ndjson`) — one JSON event object per line. This is the\nlong-running / incremental counterpart to `POST /api/format`.\nIf streaming is disabled by policy, returns 403.\n\nOptional enrichment via query flags (echoed in headers and on the\nterminating `done` event's `itemsRaw[]`):\n- `?provenance=1` — adds `_provenance` to each item\n- `?checks=retraction,oa` (or `?checks=1`) — adds `_checks` to each item\n",
        "operationId": "formatStreamCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          },
          {
            "in": "query",
            "name": "checks",
            "required": false,
            "description": "Opt-in retraction/open-access enrichment. Comma-separated tokens or `1` for all known checks.\nUnknown tokens are silently stripped. Resolved set is echoed via the `x-scholar-checks` header.\n\nTokens: `retraction`, `oa`. `1`/`true` expands to the always-available set (`retraction,oa`).\n`doaj` (DOAJ journal-indexing, ISSN-keyed) is additionally available but must be named\nexplicitly — it is gated by the server flag `ENABLE_DOAJ_CHECK` and is not part of `?checks=1`.\n",
            "schema": {
              "type": "string",
              "example": "retraction,oa"
            }
          },
          {
            "in": "query",
            "name": "provenance",
            "required": false,
            "description": "Opt-in per-item provenance manifest (`_provenance`). Set to `1`, `true`, `yes`, or `on`\nto enable the standard block; set to `full` to additionally include the large\n`full_metadata` linked-data block (funders, ORCID iDs, ROR iDs, license, trial IDs);\nset to `conflicts` to add cross-source verification (`_provenance.conflicts`), which\nalso requires the `ENABLE_PROVENANCE_CONFLICTS` server flag. Modes combine, e.g.\n`full,conflicts`. Acknowledged via the `x-scholar-provenance` response header\n(`1`, `full`, `conflicts`, or a comma-joined combination).\n",
            "schema": {
              "type": "string",
              "example": "1"
            }
          },
          {
            "in": "query",
            "name": "mode",
            "required": false,
            "description": "Resolver mode (Phase 12h). Only `strict` is supported — the fixed-order resolver chain\n(deterministic ordering within the currently-deployed `transform_version`; it is NOT a\nversion pin or a historical snapshot — see /engineering-principles \"What it does not\npromise\"). `best-effort` is reserved and not yet implemented; any value other than\n`strict` resolves to `strict`, and the `x-scholar-resolver-mode` response header then\nreports `strict` (the mode that actually ran).\n",
            "schema": {
              "type": "string",
              "enum": [
                "strict"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "lines"
                ],
                "properties": {
                  "lines": {
                    "type": "array",
                    "description": "Batch input: identifiers to resolve and format, one per element.",
                    "minItems": 1,
                    "maxItems": 500,
                    "items": {
                      "type": "string"
                    }
                  },
                  "style": {
                    "type": "string",
                    "example": "vancouver"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK (SSE stream)",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Auth-Source": {
                "description": "Where the auth came from (first-party, rapidapi, anonymous).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "first-party",
                    "rapidapi",
                    "anonymous"
                  ]
                }
              },
              "X-Auth-Plan": {
                "description": "Effective plan for this request (Free/Developer/Pro/Enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "X-Auth-Subject": {
                "description": "Subject/account identifier (user id, key hash, etc.).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              },
              "Content-Security-Policy": {
                "description": "CSP controlling resource loading.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Content-Type-Options": {
                "description": "MIME type sniffing prevention.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "nosniff"
                  ]
                }
              },
              "X-Frame-Options": {
                "description": "Clickjacking protection.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "DENY",
                    "SAMEORIGIN"
                  ]
                }
              },
              "Referrer-Policy": {
                "description": "Referrer information policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-referrer",
                    "no-referrer-when-downgrade",
                    "origin",
                    "origin-when-cross-origin",
                    "same-origin",
                    "strict-origin",
                    "strict-origin-when-cross-origin",
                    "unsafe-url"
                  ]
                }
              },
              "Permissions-Policy": {
                "description": "Feature policy controls.",
                "schema": {
                  "type": "string"
                }
              },
              "Cross-Origin-Opener-Policy": {
                "description": "Cross-origin opener policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-origin-allow-popups",
                    "unsafe-none"
                  ]
                }
              },
              "Cross-Origin-Resource-Policy": {
                "description": "Cross-origin resource policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-site",
                    "cross-origin"
                  ]
                }
              }
            },
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "type": "array",
                  "description": "Newline-delimited JSON stream: each line is one `StreamEvent`\nobject (serialized newline-delimited, NOT as a JSON array). The\nstream begins with a `start` event and ends with a `done` event.\n",
                  "items": {
                    "type": "object",
                    "description": "A single newline-delimited JSON event from `POST /api/format/stream`.\n`type` discriminates the event; `idx` is the 0-based item index (or `-1`\nfor stream-level events). The stream opens with `start` and ends with `done`.\n",
                    "required": [
                      "type",
                      "idx"
                    ],
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "start",
                          "item",
                          "error",
                          "skip-duplicate",
                          "warning",
                          "done"
                        ]
                      },
                      "idx": {
                        "type": "integer",
                        "description": "Item index, or -1 for stream-level events."
                      },
                      "render": {
                        "type": "string",
                        "description": "Rendered citation (builtin formatter `item` events)."
                      },
                      "message": {
                        "type": "string",
                        "description": "Human-readable text (`error` / `warning` events)."
                      },
                      "code": {
                        "type": "string",
                        "description": "Stable error code (`error` events)."
                      },
                      "output": {
                        "type": "string",
                        "description": "Full rendered output (terminal `done` event)."
                      },
                      "formatter": {
                        "type": "string",
                        "enum": [
                          "builtin",
                          "csl"
                        ]
                      },
                      "styleUsed": {
                        "type": "string"
                      },
                      "afterDedupe": {
                        "type": "integer"
                      },
                      "meta": {
                        "allOf": [
                          {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "Phase 12b batch summary. Aggregate counts + a duplicate-group list for a\nrequest. Additive metadata only — it never changes the formatted output.\n`resolved` counts input lines that mapped to a work, so the buckets are\nself-consistent: `linesIn === resolved + notFound + errored + skipped`,\nand `duplicates === resolved - afterDedupe`. The same shape appears on the\nstream `done` frame. Error/skip buckets are best-effort and may differ\nslightly between /api/format (dedups failing lines) and\n/api/format/stream (counts them per occurrence).\n",
                            "properties": {
                              "linesIn": {
                                "type": "integer",
                                "description": "Total input lines."
                              },
                              "resolved": {
                                "type": "integer",
                                "description": "Input lines that resolved to a work."
                              },
                              "afterDedupe": {
                                "type": "integer",
                                "description": "Distinct works after de-duplication."
                              },
                              "duplicates": {
                                "type": "integer",
                                "description": "Collapsed duplicate lines (resolved - afterDedupe)."
                              },
                              "notFound": {
                                "type": "integer",
                                "description": "Lines that resolved to no record."
                              },
                              "errored": {
                                "type": "integer",
                                "description": "Lines that failed on an upstream/other error."
                              },
                              "skipped": {
                                "type": "integer",
                                "description": "ISSN-container / ADS-without-token lines skipped."
                              },
                              "warned": {
                                "type": "integer",
                                "description": "Count of batch warning strings."
                              },
                              "duplicateGroups": {
                                "type": "array",
                                "description": "One entry per item whose input lines collapsed (>1 source line).",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "idx": {
                                      "type": "integer",
                                      "description": "First contributing input-line index."
                                    },
                                    "sourceIdxs": {
                                      "type": "array",
                                      "items": {
                                        "type": "integer"
                                      },
                                      "description": "All input-line indices that collapsed into this item."
                                    }
                                  }
                                }
                              }
                            }
                          }
                        ],
                        "description": "Batch summary on the terminal `done` event (same shape as /api/format `meta`)."
                      }
                    }
                  }
                },
                "examples": {
                  "ndjson": {
                    "summary": "One JSON event object per line",
                    "value": "{\"type\":\"start\",\"idx\":-1,\"linesIn\":1,\"warnings\":[]}\n{\"type\":\"item\",\"idx\":0,\"render\":\"Baden LR, El Sahly HM, et al. N Engl J Med. 2021;384(5):403-416.\"}\n{\"type\":\"done\",\"idx\":-1,\"output\":\"…\",\"afterDedupe\":1,\"formatter\":\"builtin\",\"styleUsed\":\"vancouver\",\"lang\":\"en-US\",\"footnote\":false,\"outputMode\":\"text\",\"errors\":[],\"meta\":{\"linesIn\":1,\"resolved\":1,\"afterDedupe\":1,\"duplicates\":0,\"notFound\":0,\"errored\":0,\"skipped\":0,\"warned\":0,\"duplicateGroups\":[]}}"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (read-only mode or streaming disabled)",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Content-Security-Policy": {
                "description": "CSP controlling resource loading.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Content-Type-Options": {
                "description": "MIME type sniffing prevention.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "nosniff"
                  ]
                }
              },
              "X-Frame-Options": {
                "description": "Clickjacking protection.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "DENY",
                    "SAMEORIGIN"
                  ]
                }
              },
              "Referrer-Policy": {
                "description": "Referrer information policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-referrer",
                    "no-referrer-when-downgrade",
                    "origin",
                    "origin-when-cross-origin",
                    "same-origin",
                    "strict-origin",
                    "strict-origin-when-cross-origin",
                    "unsafe-url"
                  ]
                }
              },
              "Permissions-Policy": {
                "description": "Feature policy controls.",
                "schema": {
                  "type": "string"
                }
              },
              "Cross-Origin-Opener-Policy": {
                "description": "Cross-origin opener policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-origin-allow-popups",
                    "unsafe-none"
                  ]
                }
              },
              "Cross-Origin-Resource-Policy": {
                "description": "Cross-origin resource policy.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "same-origin",
                    "same-site",
                    "cross-origin"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                },
                "examples": {
                  "readOnly": {
                    "value": {
                      "ok": false,
                      "code": "READ_ONLY",
                      "error": "Read-only mode"
                    }
                  },
                  "streamingDisabled": {
                    "value": {
                      "ok": false,
                      "code": "STREAMING_DISABLED",
                      "error": "Streaming disabled"
                    }
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/retraction-check": {
      "post": {
        "tags": [
          "Checks"
        ],
        "summary": "Check retraction status of a single identifier",
        "description": "Resolves the supplied identifier (DOI, PMID, PMCID, arXiv ID, ADS bibcode) to a DOI\nand returns its retraction / correction / expression-of-concern status, sourced from\nCrossref `updated-by` (Retraction Watch).\n\nResponse includes the resolved DOI, the source identifier (when different), and the\n`result` object (or `null` when no DOI could be resolved).\n",
        "operationId": "retractionCheckCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Identifier to check. Accepts DOI, PMID, PMCID, arXiv, or ADS bibcode.\nNon-DOI identifiers are resolved to a DOI before lookup.\n"
                  }
                }
              },
              "examples": {
                "doi": {
                  "summary": "DOI to check",
                  "value": {
                    "id": "10.1056/nejmoa2033700"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Retraction status",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "doi",
                    "result"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "doi": {
                      "type": "string",
                      "description": "Resolved DOI, or null when no DOI was found",
                      "nullable": true
                    },
                    "resolvedFrom": {
                      "type": "object",
                      "description": "Original identifier when different from the resolved DOI",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "value": {
                          "type": "string"
                        }
                      }
                    },
                    "reason": {
                      "type": "string",
                      "description": "Optional reason code (e.g., \"no_doi\")"
                    },
                    "result": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "isRetracted": {
                          "type": "boolean"
                        },
                        "hasCorrections": {
                          "type": "boolean"
                        },
                        "hasConcern": {
                          "type": "boolean"
                        },
                        "notices": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "type": {
                                "type": "string",
                                "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                              },
                              "label": {
                                "type": "string"
                              },
                              "doi": {
                                "type": "string",
                                "nullable": true
                              },
                              "date": {
                                "type": "string",
                                "nullable": true
                              },
                              "source": {
                                "type": "string",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "title": {
                          "type": "string",
                          "nullable": true
                        }
                      },
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "doi": "10.1056/nejmoa2033700",
                  "result": {
                    "isRetracted": false,
                    "hasCorrections": false,
                    "hasConcern": false,
                    "notices": [],
                    "title": "Efficacy and Safety of the mRNA-1273 SARS-CoV-2 Vaccine"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "502": {
            "description": "Upstream data source failure (Crossref 429 rate-limit, 5xx, or network error —\ntransient, safe to retry). Body `code` is one of `UPSTREAM_RATE_LIMITED`,\n`UPSTREAM_UNAVAILABLE`, `UPSTREAM_NETWORK_ERROR`, `UPSTREAM_ERROR`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "504": {
            "description": "Upstream data source timed out (code `UPSTREAM_TIMEOUT` — transient, safe to retry).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/oa-check": {
      "post": {
        "tags": [
          "Checks"
        ],
        "summary": "Check open-access status of a single identifier",
        "description": "Resolves the supplied identifier to a DOI and returns its open-access status,\nsourced from Unpaywall. Includes the best legal landing/PDF URL, OA status\n(gold/green/hybrid/bronze/closed), license, and version when available.\n",
        "operationId": "oaCheckCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Identifier to check. Accepts DOI, PMID, PMCID, arXiv, or ADS bibcode.\nNon-DOI identifiers are resolved to a DOI before lookup.\n"
                  }
                }
              },
              "examples": {
                "doi": {
                  "summary": "Open-access DOI",
                  "value": {
                    "id": "10.1038/s41586-020-2649-2"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Open-access status",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "doi",
                    "result"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "doi": {
                      "type": "string",
                      "nullable": true
                    },
                    "resolvedFrom": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "value": {
                          "type": "string"
                        }
                      }
                    },
                    "reason": {
                      "type": "string"
                    },
                    "result": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "isOa": {
                          "type": "boolean"
                        },
                        "oaStatus": {
                          "type": "string",
                          "enum": [
                            "gold",
                            "green",
                            "hybrid",
                            "bronze",
                            "closed"
                          ]
                        },
                        "title": {
                          "type": "string",
                          "nullable": true
                        },
                        "bestLocation": {
                          "type": "object",
                          "additionalProperties": false,
                          "properties": {
                            "url": {
                              "type": "string"
                            },
                            "hostType": {
                              "type": "string"
                            },
                            "license": {
                              "type": "string",
                              "nullable": true
                            },
                            "version": {
                              "type": "string",
                              "nullable": true
                            }
                          },
                          "nullable": true
                        },
                        "locations": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "url": {
                                "type": "string"
                              },
                              "hostType": {
                                "type": "string"
                              },
                              "license": {
                                "type": "string",
                                "nullable": true
                              },
                              "version": {
                                "type": "string",
                                "nullable": true
                              }
                            }
                          }
                        }
                      },
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "doi": "10.1038/s41586-020-2649-2",
                  "result": {
                    "isOa": true,
                    "oaStatus": "hybrid",
                    "title": "Array programming with NumPy",
                    "bestLocation": {
                      "url": "https://www.nature.com/articles/s41586-020-2649-2.pdf",
                      "hostType": "publisher",
                      "license": "cc-by",
                      "version": "publishedVersion"
                    },
                    "locations": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "502": {
            "description": "Upstream data source failure (Unpaywall 429 rate-limit, 5xx, or network error —\ntransient, safe to retry). Body `code` is one of `UPSTREAM_RATE_LIMITED`,\n`UPSTREAM_UNAVAILABLE`, `UPSTREAM_NETWORK_ERROR`, `UPSTREAM_ERROR`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "504": {
            "description": "Upstream data source timed out (code `UPSTREAM_TIMEOUT` — transient, safe to retry).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/export": {
      "post": {
        "tags": [
          "Export"
        ],
        "summary": "Export citations in a target format (batch)",
        "description": "Exports resolved citations as **RIS** or **BibTeX** for easy import into reference managers.\nInput may be raw identifiers (`text`) or pre-parsed items.\n",
        "operationId": "exportCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "description": "Optional client-chosen key for retry-safe requests on the mutating POST\nroutes. When the server has idempotency enabled, a repeated request with\nthe same key and body replays the original response verbatim (with\n`Idempotent-Replayed: true`); the same key with a different body returns\n`422`. Keys are scoped per authenticated principal (or client IP when\nanonymous), so they never collide across callers. 1–255 characters of\n`[A-Za-z0-9_.:-]`.\n",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_.:-]{1,255}$",
              "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "description": "Batch-capable. Provide `text` (one or more identifiers, one per line) or\n`items` (pre-parsed CSL-JSON); exports all entries into a single file.\nBounded by a 128 KB request body and a maximum of 500 items per request.\n",
                "oneOf": [
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "text",
                      "format"
                    ],
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "Free text with one or more identifiers, one per line (batch input)."
                      },
                      "style": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Citation style id — a builtin name or a CSL style id."
                      },
                      "lang": {
                        "type": "string",
                        "maxLength": 16,
                        "default": "en-US",
                        "description": "BCP-47 locale for the rendered citation."
                      },
                      "locale": {
                        "type": "string",
                        "maxLength": 16,
                        "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
                      },
                      "footnote": {
                        "type": "boolean",
                        "default": false,
                        "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
                      },
                      "output": {
                        "type": "string",
                        "enum": [
                          "text",
                          "html",
                          "json"
                        ],
                        "default": "text",
                        "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
                      },
                      "nocache": {
                        "type": "boolean",
                        "default": false,
                        "description": "Bypass the resolver cache for this request."
                      },
                      "format": {
                        "type": "string",
                        "description": "Export format. The route additionally accepts the internal\nspellings `bib`, `csl`, `medline` and `zotero-rdf`; the names\npublished here are the ecosystem-standard equivalents.\n",
                        "enum": [
                          "txt",
                          "ris",
                          "bibtex",
                          "csl-json",
                          "endnote-xml",
                          "endnote-refer",
                          "refworks",
                          "nbib",
                          "rdf",
                          "csv"
                        ]
                      }
                    }
                  },
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "items",
                      "format"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "description": "Batch input: pre-parsed CSL-JSON items to export, one per element.",
                        "minItems": 1,
                        "maxItems": 500,
                        "items": {
                          "type": "object",
                          "description": "CSL-JSON item"
                        }
                      },
                      "style": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Citation style id — a builtin name or a CSL style id."
                      },
                      "lang": {
                        "type": "string",
                        "maxLength": 16,
                        "default": "en-US",
                        "description": "BCP-47 locale for the rendered citation."
                      },
                      "locale": {
                        "type": "string",
                        "maxLength": 16,
                        "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
                      },
                      "footnote": {
                        "type": "boolean",
                        "default": false,
                        "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
                      },
                      "output": {
                        "type": "string",
                        "enum": [
                          "text",
                          "html",
                          "json"
                        ],
                        "default": "text",
                        "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
                      },
                      "nocache": {
                        "type": "boolean",
                        "default": false,
                        "description": "Bypass the resolver cache for this request."
                      },
                      "format": {
                        "type": "string",
                        "enum": [
                          "txt",
                          "ris",
                          "bibtex",
                          "csl-json",
                          "endnote-xml",
                          "endnote-refer",
                          "refworks",
                          "nbib",
                          "rdf",
                          "csv"
                        ]
                      }
                    }
                  }
                ]
              },
              "examples": {
                "textExample": {
                  "summary": "Single identifier",
                  "value": {
                    "text": "10.1056/nejmoa2033700",
                    "style": "vancouver",
                    "format": "ris"
                  }
                },
                "itemsExample": {
                  "summary": "Pre-parsed CSL-JSON items",
                  "value": {
                    "items": [
                      {
                        "title": "Example title",
                        "type": "article-journal"
                      }
                    ],
                    "style": "ama",
                    "format": "bibtex"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Exported bibliography file. The concrete `Content-Type` varies by\n`format` (e.g. `text/x-bibtex`, `application/x-research-info-systems`,\n`application/vnd.citationstyles.csl+json`, `text/csv`, `application/xml`);\nthe body is the file content, delivered as an attachment.\n",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Transform-Version": {
                "description": "Public, monotonically-versioned tag for normalisation + formatting\nlogic — returned on every response. Serves as the active API version\nunder the header-based versioning scheme.\n",
                "schema": {
                  "type": "string",
                  "example": "2026-08-18"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to \"true\" when this response was replayed from a prior request with\nthe same `Idempotency-Key` (not freshly computed).\n",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "Content-Disposition": {
                "description": "Attachment filename for the exported file.",
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"citations.ris\""
                }
              },
              "X-Scholar-Batch-Lines-In": {
                "description": "Number of input lines received by the export batch.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Batch-Resolved": {
                "description": "Number of input lines that resolved to a record.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Batch-After-Dedupe": {
                "description": "Number of items actually serialized into the exported file (after dedupe).",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Batch-Duplicates": {
                "description": "Number of resolved rows dropped by dedupe (resolved - after-dedupe).",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Batch-Not-Found": {
                "description": "Number of input lines with no matching record.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Batch-Errored": {
                "description": "Number of input lines that failed for a non-not-found reason.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Batch-Skipped": {
                "description": "Number of input lines skipped before resolution (e.g. ISSN-only lines).",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Batch-Warned": {
                "description": "Number of warnings emitted via the response warning headers.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "Exported file content (format-specific; see the response Content-Type)."
                },
                "example": "TY  - JOUR\nTI  - Efficacy and Safety of the mRNA-1273 SARS-CoV-2 Vaccine\nAU  - Baden, Lindsey R.\nJO  - New England Journal of Medicine\nVL  - 384\nIS  - 5\nSP  - 403\nEP  - 416\nPY  - 2021\nDO  - 10.1056/nejmoa2033700\nER  -"
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Typed error (catch-all). Body is the shared `ErrorResponse` envelope and\nthe stable code is mirrored in the `X-Error-Code` response header.\n",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/verify": {
      "post": {
        "tags": [
          "Verify"
        ],
        "summary": "Verify a claimed citation against its resolved record",
        "description": "Takes a single *claimed* citation and returns whether the record it\nresolves to matches what the caller claimed — detecting the dominant\nAI-era fabrication pattern (a real, resolving identifier paired with a\nfabricated title).\n\nVerdict is one of `matched | mismatch | ambiguous | not_found`, each\nwith a `confidence` tier (`high | medium | low`).\n200 OK on every produced verdict — the verdict IS the answer, not a\nfailure mode. 4xx/5xx only for protocol errors: malformed JSON, a\nmissing `claimed.title` (`400 MISSING_TITLE`), or resolver upstream\nfailure (`502`).\n\n`claimed.title` is required; an identifier is optional. When an\nidentifier is supplied it is resolved and compared; on a title mismatch\n(or an identifier that does not resolve) the route falls back to a\ntitle-search (Crossref + PubMed + OpenAlex) to tell a wrong-identifier\ncitation (`ambiguous`) apart from one that resolves nowhere\n(`not_found`). With no identifier and a title too sparse to search\nsafely, the verdict is `not_found` with\n`_provenance.skipped_reason: \"insufficient_claim\"`. Optional Stage-3 LLM\nscreening of low-confidence mismatches is gated to paid / authenticated\ncallers.\n\nKnown limitations — what the verifier is weak on, and what it does NOT\ntell you (retraction and open-access status are separate signals) — are\npublished at\nhttps://scholar-sidekick.com/citation-integrity/known-failures.md.\n\nMotivation: Topaz et al., *The Lancet* 2026;407(10541):1779-1781\n(doi:10.1016/S0140-6736(26)00603-3) document that the dominant\nbiomedical citation-fabrication pattern is a valid identifier paired\nwith a fabricated title — every resolvable case in their Supplementary\nAppendix 2 is caught by this endpoint.\n",
        "operationId": "verifyCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "description": "Optional client-chosen key for retry-safe requests on the mutating POST\nroutes. When the server has idempotency enabled, a repeated request with\nthe same key and body replays the original response verbatim (with\n`Idempotent-Replayed: true`); the same key with a different body returns\n`422`. Keys are scoped per authenticated principal (or client IP when\nanonymous), so they never collide across callers. 1–255 characters of\n`[A-Za-z0-9_.:-]`.\n",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_.:-]{1,255}$",
              "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "claimed"
                ],
                "properties": {
                  "claimed": {
                    "type": "object",
                    "additionalProperties": false,
                    "description": "Caller-supplied citation under verification. `title` is required (a\nmissing title returns `400 MISSING_TITLE`). An identifier is optional;\nwith none, the verifier title-searches when the title is specific\nenough, otherwise returns `not_found` with\n`_provenance.skipped_reason: \"insufficient_claim\"`.\n",
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 2000
                      },
                      "authors": {
                        "type": "array",
                        "maxItems": 50,
                        "items": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "family"
                          ],
                          "properties": {
                            "family": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 200
                            },
                            "given": {
                              "type": "string",
                              "maxLength": 200
                            }
                          }
                        }
                      },
                      "year": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                      },
                      "container": {
                        "type": "string",
                        "maxLength": 500
                      },
                      "doi": {
                        "type": "string",
                        "maxLength": 200
                      },
                      "pmid": {
                        "type": "string",
                        "maxLength": 50
                      },
                      "pmcid": {
                        "type": "string",
                        "maxLength": 50
                      },
                      "isbn": {
                        "type": "string",
                        "maxLength": 50
                      },
                      "arxiv": {
                        "type": "string",
                        "maxLength": 50
                      },
                      "issn": {
                        "type": "string",
                        "maxLength": 50
                      },
                      "ads": {
                        "type": "string",
                        "maxLength": 50
                      },
                      "whoIrisUrl": {
                        "type": "string",
                        "maxLength": 2000
                      }
                    }
                  },
                  "options": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "bypassCache": {
                        "type": "boolean"
                      },
                      "screen_with_llm": {
                        "type": "boolean",
                        "description": "Opt-in Stage 3 LLM screen (Phase 12i.3). Fires only when the\npre-LLM verdict is `mismatch` with `confidence: low` (the\ninformal-abbreviation false-positive bucket). Gated:\nauthenticated first-party callers and paid RapidAPI tiers\nonly. Anonymous / free callers receive `400\nLLM_SCREEN_FORBIDDEN`. Per-day budget cap is configurable\nvia `LLM_VERIFY_DAILY_BUDGET_USD` (default $5/day); when\nexceeded the request still returns its non-LLM verdict\nwith `_provenance.llm_screen.reason = daily_budget_exceeded`.\n"
                      }
                    }
                  }
                }
              },
              "examples": {
                "matchedExample": {
                  "summary": "Matched citation (DOI + claimed metadata align)",
                  "value": {
                    "claimed": {
                      "title": "Fabricated citations: an audit across 2·5 million biomedical papers",
                      "authors": [
                        {
                          "family": "Topaz",
                          "given": "M"
                        }
                      ],
                      "year": 2026,
                      "container": "The Lancet",
                      "doi": "10.1016/S0140-6736(26)00603-3"
                    }
                  }
                },
                "mismatchExample": {
                  "summary": "Mismatch — real DOI, fabricated title",
                  "value": {
                    "claimed": {
                      "title": "Microglial Modulation via Cannabinoid Receptor 2 Alleviates Fibromyalgia-Related Central Sensitization and Pain Hypersensitivity",
                      "authors": [
                        {
                          "family": "Chen",
                          "given": "F"
                        }
                      ],
                      "year": 2023,
                      "container": "Neuroscience",
                      "doi": "10.1016/j.neuroscience.2023.02.008"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification verdict produced",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to \"true\" when this response was replayed from a prior request with\nthe same `Idempotency-Key` (not freshly computed).\n",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "X-Scholar-Transform-Version": {
                "schema": {
                  "type": "string",
                  "example": "2026-08-18"
                },
                "description": "Public, monotonically-versioned tag for normalisation + formatting logic."
              },
              "X-Scholar-Verify-Version": {
                "schema": {
                  "type": "string",
                  "example": "2026-08-03"
                },
                "description": "Public, monotonically-versioned tag for the verifier pipeline.\nBumped when verdict semantics change.\n"
              },
              "X-Scholar-Verify-Verdict": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "matched",
                    "mismatch",
                    "not_found",
                    "ambiguous"
                  ]
                },
                "description": "Verdict surfaced for log-scraping without parsing the JSON body."
              },
              "X-Scholar-Verify-Confidence": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "high",
                    "medium",
                    "low"
                  ]
                },
                "description": "Confidence tier of the verdict."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "verdict",
                    "confidence",
                    "matched",
                    "mismatches",
                    "_provenance"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "verdict": {
                      "type": "string",
                      "enum": [
                        "matched",
                        "mismatch",
                        "not_found",
                        "ambiguous"
                      ]
                    },
                    "confidence": {
                      "type": "string",
                      "enum": [
                        "high",
                        "medium",
                        "low"
                      ]
                    },
                    "matched": {
                      "description": "Best record the verifier matched the claim to (resolver record\non the identifier path, or top search candidate on the no-id\npath). `null` when nothing meaningful matched.\n",
                      "type": "object",
                      "nullable": true
                    },
                    "mismatches": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "field",
                          "similarity"
                        ],
                        "properties": {
                          "field": {
                            "type": "string",
                            "enum": [
                              "title",
                              "first_author",
                              "year",
                              "container",
                              "coauthor"
                            ],
                            "description": "Which field disagreed. `coauthor` rows are emitted only when the\nco-author cross-check is enabled server-side, one row per claimed\nco-author that matched no author on the resolved record; unlike the\nother fields they never drive a `mismatch` — they downgrade\n`matched` to `ambiguous` (review).\n"
                          },
                          "claimed": {
                            "oneOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "number"
                              }
                            ]
                          },
                          "resolved": {
                            "oneOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "number"
                              }
                            ]
                          },
                          "similarity": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1
                          }
                        }
                      }
                    },
                    "candidates": {
                      "type": "array",
                      "description": "Title-search alternatives, ranked by similarity (best first).\nPresent whenever the search stage ran; absent on the compare-only\nfast path.\n",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "item",
                          "registries",
                          "score"
                        ],
                        "description": "A title-search alternative surfaced when the verifier cannot confirm\nthe supplied identifier matches the claimed metadata. Present on\nverdicts `matched` (no-identifier path), `ambiguous`, `mismatch`\n(post-12i.2), and `not_found` (post-12i.2).\n",
                        "properties": {
                          "item": {
                            "type": "object",
                            "description": "BiblioItem matching the claim's title via search."
                          },
                          "registries": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "enum": [
                                "crossref",
                                "pubmed",
                                "openalex"
                              ]
                            }
                          },
                          "score": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1,
                            "description": "Title similarity (0-1) against the claim."
                          }
                        }
                      }
                    },
                    "_provenance": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "stages_run",
                        "resolved_via"
                      ],
                      "properties": {
                        "stages_run": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "compare",
                              "search",
                              "llm_screen",
                              "containment"
                            ]
                          }
                        },
                        "resolved_via": {
                          "description": "Identifier of the resolver-source service (e.g., `crossref`, `pubmed`).",
                          "type": "string",
                          "nullable": true
                        },
                        "method": {
                          "type": "string",
                          "enum": [
                            "compare",
                            "containment"
                          ],
                          "description": "Which verdict method produced this entry. Absent (or `compare`) is the\ndefault single-citation path: a clean claimed title compared to the\nresolved title via full-string similarity. `containment` is the\nprose-reference path (`/api/audit` `references[]` input, e.g. a `.docx`\nupload): no clean title is available, so the resolved title is checked\nfor token-containment within the raw reference text.\n"
                        },
                        "containment": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "score",
                            "matched_tokens",
                            "total_tokens"
                          ],
                          "description": "Containment scoring detail — present only on containment-method entries.",
                          "properties": {
                            "score": {
                              "type": "number",
                              "description": "Fraction (0-1) of the resolved title's significant tokens found in the reference text."
                            },
                            "matched_tokens": {
                              "type": "integer"
                            },
                            "total_tokens": {
                              "type": "integer"
                            },
                            "corroboration": {
                              "type": "string",
                              "enum": [
                                "corroborated",
                                "refuted",
                                "partial",
                                "unavailable"
                              ],
                              "description": "Author+year second signal, used to disambiguate a LOW title score —\na translated or reworded genuine citation and a fabricated title\nboth score near zero on title tokens alone, but author surnames\nand the year are language-invariant.\n- `corroborated`: the resolved record's author AND year appear in\n  the reference, so the citation points at this work however the\n  title was written. The entry is rescued to `ambiguous` (review)\n  and never flagged as a fabrication; a caveat explains why.\n- `refuted`: the record has a usable surname and a year and\n  NEITHER appears, so two independent signals agree — a wider\n  mismatch cutoff applies.\n- `partial`: exactly one of the two appears. That is not\n  disagreement — a genuine citation that omits the year, or\n  romanises an author differently (\"Mueller\" vs \"Müller\"), trips\n  this — so the conservative cutoff applies.\n- `unavailable`: the record carries no usable surname or no year,\n  so there is nothing to corroborate with; the conservative\n  near-zero-overlap cutoff applies.\n"
                            }
                          }
                        },
                        "v1_limitations": {
                          "type": "array",
                          "deprecated": true,
                          "items": {
                            "type": "string"
                          },
                          "description": "Deprecated since 12i.2 and never emitted by the current route.\nPre-12i.2 the verifier emitted `no_identifier_provided_in_v1` here\nwhen the claim lacked an identifier; the active title-search path\nreplaced that case. Superseded by `caveats`.\n"
                        },
                        "caveats": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Point-of-use limitations of this verdict (SPEC §10). Each string is\nemitted only when deterministically TRUE of the comparison — e.g.\n`\"resolved via title-search; the supplied identifier did not\nresolve\"`, `\"container-only identifier (ISSN); verifies the journal,\nnot a specific work\"`, `\"title is non-Latin script; character-level\nsimilarity is weaker here\"`, `\"verdict reflects a publication-year\ngap\"`, `\"group author could not be cross-checked against the\nrecord\"`, `\"a claimed co-author could not be found on the resolved\nrecord\"`, `\"no record found in the scholarly registries searched;\nsources outside them (standards, software repositories, model cards,\ninstitutional reports) are not indexed here\"`. Absent (not an empty\narray) on a clean high-confidence `matched`.\n"
                        },
                        "skipped_reason": {
                          "type": "string",
                          "enum": [
                            "insufficient_claim",
                            "container_only",
                            "no_identifier",
                            "sparse_resolved_title"
                          ],
                          "description": "Present when the verifier short-circuited before searching. Verdict is\n`not_found` in these cases; absent on normal verdicts.\n- `insufficient_claim`: the claim carried no identifier and a title too\n  sparse to title-search safely (e.g. a single token).\n- `container_only`: the identifier resolved to a journal/container\n  (e.g. an ISSN), not a work — there is no paper to verify (Phase 12j).\n- `no_identifier`: (containment path) the reference text carried no\n  detectable identifier, so there was nothing to resolve against.\n- `sparse_resolved_title`: (containment path) the identifier resolved,\n  but the record's title is too short to score containment safely.\n"
                        },
                        "registries_searched": {
                          "type": "array",
                          "description": "Per-registry status block surfaced when the title-search\naggregator ran. Absent on the compare-only fast path.\n",
                          "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "required": [
                              "registry",
                              "ok",
                              "count"
                            ],
                            "properties": {
                              "registry": {
                                "type": "string",
                                "enum": [
                                  "crossref",
                                  "pubmed",
                                  "openalex"
                                ]
                              },
                              "ok": {
                                "type": "boolean"
                              },
                              "count": {
                                "type": "integer",
                                "minimum": 0
                              },
                              "reason": {
                                "type": "string",
                                "description": "Failure reason (e.g., `upstream_error`, `invalid_input`) when\nthe registry adapter did not return results.\n"
                              }
                            }
                          }
                        },
                        "llm_screen": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "applied"
                          ],
                          "description": "LLM screen telemetry (Phase 12i.3). Emitted on the response\nenvelope whenever the caller passed `options.screen_with_llm:\ntrue`. `applied: true` means a model call ran and produced a\nstructured verdict; `applied: false` carries a `reason` field\nexplaining why the screen was skipped.\n",
                          "properties": {
                            "applied": {
                              "type": "boolean"
                            },
                            "model": {
                              "type": "string",
                              "description": "Model slug used for the screen (e.g., `anthropic/claude-haiku-4.5`)."
                            },
                            "prompt_version": {
                              "type": "string",
                              "description": "Prompt revision identifier — bumped with `SCHOLAR_VERIFY_VERSION`."
                            },
                            "verdict": {
                              "type": "string",
                              "enum": [
                                "informal_abbreviation",
                                "different_paper",
                                "uncertain"
                              ],
                              "description": "LLM classification. `informal_abbreviation` upgrades the\nverdict to `matched / low`; `different_paper` keeps `mismatch`\nand raises confidence to `high`; `uncertain` leaves the\npre-LLM verdict unchanged.\n"
                            },
                            "reasoning": {
                              "type": "string",
                              "description": "Justification (≤2000 chars) emitted alongside the verdict."
                            },
                            "cost_usd": {
                              "type": "number",
                              "minimum": 0,
                              "description": "Approximate USD cost of the model call, computed from token\nusage and published list prices. Used by the daily-budget\nguard at `LLM_VERIFY_DAILY_BUDGET_USD`.\n"
                            },
                            "reason": {
                              "type": "string",
                              "enum": [
                                "verdict_not_eligible",
                                "daily_budget_exceeded",
                                "no_gateway",
                                "upstream_error",
                                "malformed_response"
                              ],
                              "description": "Set when `applied: false`. `verdict_not_eligible` means the\npre-LLM verdict was not `mismatch / low` so no model call was\nattempted.\n"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "matched": {
                    "summary": "Claimed metadata matches the resolved record",
                    "value": {
                      "ok": true,
                      "verdict": "matched",
                      "confidence": "high",
                      "matched": {
                        "title": "Fabricated citations: an audit across 2·5 million biomedical papers",
                        "DOI": "10.1016/S0140-6736(26)00603-3",
                        "type": "article-journal"
                      },
                      "mismatches": [],
                      "_provenance": {
                        "stages_run": [
                          "compare"
                        ],
                        "resolved_via": "crossref"
                      }
                    }
                  },
                  "mismatch": {
                    "summary": "Real DOI paired with a fabricated title (the Topaz et al. pattern)",
                    "value": {
                      "ok": true,
                      "verdict": "mismatch",
                      "confidence": "high",
                      "matched": {
                        "title": "Fabricated citations: an audit across 2·5 million biomedical papers",
                        "DOI": "10.1016/S0140-6736(26)00603-3",
                        "type": "article-journal"
                      },
                      "mismatches": [
                        {
                          "field": "title",
                          "claimed": "A Novel Deep Learning Framework for Real-Time Citation Verification",
                          "resolved": "Fabricated citations: an audit across 2·5 million biomedical papers",
                          "similarity": 0.12
                        }
                      ],
                      "_provenance": {
                        "stages_run": [
                          "compare"
                        ],
                        "resolved_via": "crossref"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "413": {
            "description": "Request body exceeds the maximum allowed size.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "502": {
            "description": "Resolver upstream failure (transient — safe to retry).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/audit": {
      "post": {
        "tags": [
          "Verify"
        ],
        "summary": "Audit a whole bibliography for fabrication + retraction",
        "description": "The batch counterpart to `/api/verify`. Takes a whole bibliography —\neither raw `bibliography` text (BibTeX / RIS / CSL-JSON, format\nauto-detected) or a `claims[]` array of pre-parsed references — and\nruns the same fabrication check on every entry (a real, resolving\nidentifier paired with a title that does not match the resolved paper;\nTopaz et al., *The Lancet* 2026). Each resolved entry also gets a\nretraction lookup (default; pass `checks: []` to skip).\n\nProvide **exactly one** of `bibliography` or `claims`. Capped at 25\nentries per call — excess is dropped and reported via `truncated`.\n\n200 OK on every produced audit: a per-citation mismatch / not_found /\nretracted is a body field, not an HTTP error. Per-entry leniency means\none entry that fails to resolve becomes `status: \"error\"` without\nfailing the batch. 4xx only for protocol errors (bad content-type,\nmalformed JSON, oversize body → `413`, schema violation). A total\nverification outage (every entry errored upstream) returns `502`.\n\nThis audits citation IDENTITY at corpus scale; it does NOT check whether\na source supports the claim it is cited for.\n",
        "operationId": "auditCreate",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "description": "Optional client-chosen key for retry-safe requests on the mutating POST\nroutes. When the server has idempotency enabled, a repeated request with\nthe same key and body replays the original response verbatim (with\n`Idempotent-Replayed: true`); the same key with a different body returns\n`422`. Keys are scoped per authenticated principal (or client IP when\nanonymous), so they never collide across callers. 1–255 characters of\n`[A-Za-z0-9_.:-]`.\n",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_.:-]{1,255}$",
              "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "description": "Provide EXACTLY ONE of `bibliography` (raw text), `claims` (array), or\n`references` (array of raw reference strings).\n",
                "properties": {
                  "bibliography": {
                    "type": "string",
                    "maxLength": 131072,
                    "description": "Raw BibTeX / RIS / CSL-JSON text. Format is auto-detected unless `format` is set."
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "bibtex",
                      "ris",
                      "csl-json"
                    ],
                    "description": "Override format auto-detection for `bibliography`."
                  },
                  "claims": {
                    "type": "array",
                    "maxItems": 25,
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "title"
                      ],
                      "description": "A single pre-parsed citation for the `claims[]` path. `title` is required.",
                      "properties": {
                        "title": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 2000
                        },
                        "authors": {
                          "type": "array",
                          "maxItems": 50,
                          "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "required": [
                              "family"
                            ],
                            "properties": {
                              "family": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 200
                              },
                              "given": {
                                "type": "string",
                                "maxLength": 200
                              }
                            }
                          }
                        },
                        "year": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9999
                        },
                        "container": {
                          "type": "string",
                          "maxLength": 500
                        },
                        "doi": {
                          "type": "string",
                          "maxLength": 200
                        },
                        "pmid": {
                          "type": "string",
                          "maxLength": 50
                        },
                        "pmcid": {
                          "type": "string",
                          "maxLength": 50
                        },
                        "isbn": {
                          "type": "string",
                          "maxLength": 50
                        },
                        "arxiv": {
                          "type": "string",
                          "maxLength": 50
                        },
                        "issn": {
                          "type": "string",
                          "maxLength": 50
                        },
                        "ads": {
                          "type": "string",
                          "maxLength": 50
                        },
                        "whoIrisUrl": {
                          "type": "string",
                          "maxLength": 2000
                        }
                      }
                    }
                  },
                  "references": {
                    "type": "array",
                    "maxItems": 25,
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 5000
                    },
                    "description": "Raw prose reference paragraphs (e.g. extracted from a `.docx`\nmanuscript). Each is verified via the CONTAINMENT method: its\nidentifier is resolved and the resolved title is checked for\ntoken-containment in the reference text (no clean claimed title is\nparsed). Response entries carry `_provenance.method: \"containment\"`;\nthe `x-scholar-containment-version` header pins the method version.\n"
                  },
                  "options": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "bypassCache": {
                        "type": "boolean"
                      },
                      "screen_with_llm": {
                        "type": "boolean",
                        "description": "Opt-in Stage 3 LLM screen per entry (same gating as /api/verify). Default false."
                      },
                      "checks": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "retraction"
                          ]
                        },
                        "description": "Per-entry enrichment checks. Default: [retraction]. Pass [] to skip."
                      }
                    }
                  }
                }
              },
              "examples": {
                "bibliographyExample": {
                  "summary": "Raw BibTeX bibliography (mixed real + fabricated)",
                  "value": {
                    "bibliography": "@article{a, title={Fabricated citations: an audit across 2.5 million biomedical papers}, doi={10.1016/S0140-6736(26)00603-3}}\n@article{b, title={An invented title}, doi={10.1016/j.neuroscience.2023.02.008}}"
                  }
                },
                "claimsExample": {
                  "summary": "Pre-parsed claims array",
                  "value": {
                    "claims": [
                      {
                        "title": "Fabricated citations: an audit across 2.5 million biomedical papers",
                        "doi": "10.1016/S0140-6736(26)00603-3"
                      }
                    ],
                    "options": {
                      "checks": [
                        "retraction"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Audit produced (per-entry verdicts + corpus summary)",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "Idempotent-Replayed": {
                "description": "Set to \"true\" when this response was replayed from a prior request with\nthe same `Idempotency-Key` (not freshly computed).\n",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              },
              "X-Scholar-Transform-Version": {
                "schema": {
                  "type": "string",
                  "example": "2026-08-18"
                },
                "description": "Public, monotonically-versioned tag for normalisation + formatting logic."
              },
              "X-Scholar-Verify-Version": {
                "schema": {
                  "type": "string",
                  "example": "2026-08-03"
                },
                "description": "Public, monotonically-versioned tag for the verifier pipeline."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "format",
                    "entries",
                    "parseErrors",
                    "truncated",
                    "summary"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "format": {
                      "type": "string",
                      "enum": [
                        "bibtex",
                        "ris",
                        "csl-json",
                        null
                      ],
                      "description": "Detected input format, or null for the claims[] path.",
                      "nullable": true
                    },
                    "entries": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "description": "One result per verifiable entry. `status: \"ok\"` carries a verdict;\n`status: \"error\"` marks a per-entry upstream failure (the batch is not\nfailed by one bad entry).\n",
                        "required": [
                          "index",
                          "status"
                        ],
                        "properties": {
                          "index": {
                            "type": "integer",
                            "description": "1-based position in the input batch."
                          },
                          "sourceKey": {
                            "type": "string",
                            "description": "BibTeX key / RIS record index / CSL-JSON id, when present."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "ok",
                              "error"
                            ]
                          },
                          "error": {
                            "type": "string",
                            "description": "Present only on status=error."
                          },
                          "verdict": {
                            "type": "string",
                            "enum": [
                              "matched",
                              "mismatch",
                              "not_found",
                              "ambiguous"
                            ]
                          },
                          "confidence": {
                            "type": "string",
                            "enum": [
                              "high",
                              "medium",
                              "low"
                            ]
                          },
                          "matched": {
                            "type": "object",
                            "description": "Resolver-returned BiblioItem.",
                            "nullable": true
                          },
                          "mismatches": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "field",
                                "similarity"
                              ],
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "enum": [
                                    "title",
                                    "first_author",
                                    "year",
                                    "container",
                                    "coauthor"
                                  ],
                                  "description": "Which field disagreed. `coauthor` rows are emitted only when the\nco-author cross-check is enabled server-side, one row per claimed\nco-author that matched no author on the resolved record; unlike the\nother fields they never drive a `mismatch` — they downgrade\n`matched` to `ambiguous` (review).\n"
                                },
                                "claimed": {
                                  "oneOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "number"
                                    }
                                  ]
                                },
                                "resolved": {
                                  "oneOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "number"
                                    }
                                  ]
                                },
                                "similarity": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1
                                }
                              }
                            }
                          },
                          "candidates": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "item",
                                "registries",
                                "score"
                              ],
                              "description": "A title-search alternative surfaced when the verifier cannot confirm\nthe supplied identifier matches the claimed metadata. Present on\nverdicts `matched` (no-identifier path), `ambiguous`, `mismatch`\n(post-12i.2), and `not_found` (post-12i.2).\n",
                              "properties": {
                                "item": {
                                  "type": "object",
                                  "description": "BiblioItem matching the claim's title via search."
                                },
                                "registries": {
                                  "type": "array",
                                  "items": {
                                    "type": "string",
                                    "enum": [
                                      "crossref",
                                      "pubmed",
                                      "openalex"
                                    ]
                                  }
                                },
                                "score": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1,
                                  "description": "Title similarity (0-1) against the claim."
                                }
                              }
                            }
                          },
                          "retraction": {
                            "type": "object",
                            "additionalProperties": false,
                            "description": "Per-entry retraction status. `checked` is false when retraction was not\nrequested, the entry had no resolvable DOI, or an upstream error was\nswallowed. `null` when `checks` did not include `retraction`.\n",
                            "required": [
                              "checked",
                              "doi",
                              "isRetracted",
                              "hasCorrections",
                              "hasConcern",
                              "notices"
                            ],
                            "properties": {
                              "checked": {
                                "type": "boolean"
                              },
                              "doi": {
                                "type": "string",
                                "nullable": true
                              },
                              "isRetracted": {
                                "type": "boolean"
                              },
                              "hasCorrections": {
                                "type": "boolean"
                              },
                              "hasConcern": {
                                "type": "boolean"
                              },
                              "notices": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "properties": {
                                    "type": {
                                      "type": "string",
                                      "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                                    },
                                    "label": {
                                      "type": "string"
                                    },
                                    "doi": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "date": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "source": {
                                      "type": "string",
                                      "nullable": true
                                    }
                                  }
                                }
                              }
                            },
                            "nullable": true
                          },
                          "_provenance": {
                            "type": "object",
                            "additionalProperties": false,
                            "required": [
                              "stages_run",
                              "resolved_via"
                            ],
                            "properties": {
                              "stages_run": {
                                "type": "array",
                                "items": {
                                  "type": "string",
                                  "enum": [
                                    "compare",
                                    "search",
                                    "llm_screen",
                                    "containment"
                                  ]
                                }
                              },
                              "resolved_via": {
                                "description": "Identifier of the resolver-source service (e.g., `crossref`, `pubmed`).",
                                "type": "string",
                                "nullable": true
                              },
                              "method": {
                                "type": "string",
                                "enum": [
                                  "compare",
                                  "containment"
                                ],
                                "description": "Which verdict method produced this entry. Absent (or `compare`) is the\ndefault single-citation path: a clean claimed title compared to the\nresolved title via full-string similarity. `containment` is the\nprose-reference path (`/api/audit` `references[]` input, e.g. a `.docx`\nupload): no clean title is available, so the resolved title is checked\nfor token-containment within the raw reference text.\n"
                              },
                              "containment": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                  "score",
                                  "matched_tokens",
                                  "total_tokens"
                                ],
                                "description": "Containment scoring detail — present only on containment-method entries.",
                                "properties": {
                                  "score": {
                                    "type": "number",
                                    "description": "Fraction (0-1) of the resolved title's significant tokens found in the reference text."
                                  },
                                  "matched_tokens": {
                                    "type": "integer"
                                  },
                                  "total_tokens": {
                                    "type": "integer"
                                  },
                                  "corroboration": {
                                    "type": "string",
                                    "enum": [
                                      "corroborated",
                                      "refuted",
                                      "partial",
                                      "unavailable"
                                    ],
                                    "description": "Author+year second signal, used to disambiguate a LOW title score —\na translated or reworded genuine citation and a fabricated title\nboth score near zero on title tokens alone, but author surnames\nand the year are language-invariant.\n- `corroborated`: the resolved record's author AND year appear in\n  the reference, so the citation points at this work however the\n  title was written. The entry is rescued to `ambiguous` (review)\n  and never flagged as a fabrication; a caveat explains why.\n- `refuted`: the record has a usable surname and a year and\n  NEITHER appears, so two independent signals agree — a wider\n  mismatch cutoff applies.\n- `partial`: exactly one of the two appears. That is not\n  disagreement — a genuine citation that omits the year, or\n  romanises an author differently (\"Mueller\" vs \"Müller\"), trips\n  this — so the conservative cutoff applies.\n- `unavailable`: the record carries no usable surname or no year,\n  so there is nothing to corroborate with; the conservative\n  near-zero-overlap cutoff applies.\n"
                                  }
                                }
                              },
                              "v1_limitations": {
                                "type": "array",
                                "deprecated": true,
                                "items": {
                                  "type": "string"
                                },
                                "description": "Deprecated since 12i.2 and never emitted by the current route.\nPre-12i.2 the verifier emitted `no_identifier_provided_in_v1` here\nwhen the claim lacked an identifier; the active title-search path\nreplaced that case. Superseded by `caveats`.\n"
                              },
                              "caveats": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Point-of-use limitations of this verdict (SPEC §10). Each string is\nemitted only when deterministically TRUE of the comparison — e.g.\n`\"resolved via title-search; the supplied identifier did not\nresolve\"`, `\"container-only identifier (ISSN); verifies the journal,\nnot a specific work\"`, `\"title is non-Latin script; character-level\nsimilarity is weaker here\"`, `\"verdict reflects a publication-year\ngap\"`, `\"group author could not be cross-checked against the\nrecord\"`, `\"a claimed co-author could not be found on the resolved\nrecord\"`, `\"no record found in the scholarly registries searched;\nsources outside them (standards, software repositories, model cards,\ninstitutional reports) are not indexed here\"`. Absent (not an empty\narray) on a clean high-confidence `matched`.\n"
                              },
                              "skipped_reason": {
                                "type": "string",
                                "enum": [
                                  "insufficient_claim",
                                  "container_only",
                                  "no_identifier",
                                  "sparse_resolved_title"
                                ],
                                "description": "Present when the verifier short-circuited before searching. Verdict is\n`not_found` in these cases; absent on normal verdicts.\n- `insufficient_claim`: the claim carried no identifier and a title too\n  sparse to title-search safely (e.g. a single token).\n- `container_only`: the identifier resolved to a journal/container\n  (e.g. an ISSN), not a work — there is no paper to verify (Phase 12j).\n- `no_identifier`: (containment path) the reference text carried no\n  detectable identifier, so there was nothing to resolve against.\n- `sparse_resolved_title`: (containment path) the identifier resolved,\n  but the record's title is too short to score containment safely.\n"
                              },
                              "registries_searched": {
                                "type": "array",
                                "description": "Per-registry status block surfaced when the title-search\naggregator ran. Absent on the compare-only fast path.\n",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "registry",
                                    "ok",
                                    "count"
                                  ],
                                  "properties": {
                                    "registry": {
                                      "type": "string",
                                      "enum": [
                                        "crossref",
                                        "pubmed",
                                        "openalex"
                                      ]
                                    },
                                    "ok": {
                                      "type": "boolean"
                                    },
                                    "count": {
                                      "type": "integer",
                                      "minimum": 0
                                    },
                                    "reason": {
                                      "type": "string",
                                      "description": "Failure reason (e.g., `upstream_error`, `invalid_input`) when\nthe registry adapter did not return results.\n"
                                    }
                                  }
                                }
                              },
                              "llm_screen": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                  "applied"
                                ],
                                "description": "LLM screen telemetry (Phase 12i.3). Emitted on the response\nenvelope whenever the caller passed `options.screen_with_llm:\ntrue`. `applied: true` means a model call ran and produced a\nstructured verdict; `applied: false` carries a `reason` field\nexplaining why the screen was skipped.\n",
                                "properties": {
                                  "applied": {
                                    "type": "boolean"
                                  },
                                  "model": {
                                    "type": "string",
                                    "description": "Model slug used for the screen (e.g., `anthropic/claude-haiku-4.5`)."
                                  },
                                  "prompt_version": {
                                    "type": "string",
                                    "description": "Prompt revision identifier — bumped with `SCHOLAR_VERIFY_VERSION`."
                                  },
                                  "verdict": {
                                    "type": "string",
                                    "enum": [
                                      "informal_abbreviation",
                                      "different_paper",
                                      "uncertain"
                                    ],
                                    "description": "LLM classification. `informal_abbreviation` upgrades the\nverdict to `matched / low`; `different_paper` keeps `mismatch`\nand raises confidence to `high`; `uncertain` leaves the\npre-LLM verdict unchanged.\n"
                                  },
                                  "reasoning": {
                                    "type": "string",
                                    "description": "Justification (≤2000 chars) emitted alongside the verdict."
                                  },
                                  "cost_usd": {
                                    "type": "number",
                                    "minimum": 0,
                                    "description": "Approximate USD cost of the model call, computed from token\nusage and published list prices. Used by the daily-budget\nguard at `LLM_VERIFY_DAILY_BUDGET_USD`.\n"
                                  },
                                  "reason": {
                                    "type": "string",
                                    "enum": [
                                      "verdict_not_eligible",
                                      "daily_budget_exceeded",
                                      "no_gateway",
                                      "upstream_error",
                                      "malformed_response"
                                    ],
                                    "description": "Set when `applied: false`. `verdict_not_eligible` means the\npre-LLM verdict was not `mismatch / low` so no model call was\nattempted.\n"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "parseErrors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "index",
                          "error",
                          "message"
                        ],
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "error": {
                            "type": "string",
                            "description": "e.g. \"missing_title\", \"invalid_syntax\", \"empty_entry\", \"unsupported_type\"."
                          },
                          "message": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "truncated": {
                      "type": "integer",
                      "description": "Entries dropped beyond the 25-entry cap."
                    },
                    "summary": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "total",
                        "matched",
                        "mismatch",
                        "ambiguous",
                        "not_found",
                        "errored",
                        "retracted"
                      ],
                      "description": "Corpus roll-up (a pure function of `entries`).",
                      "properties": {
                        "total": {
                          "type": "integer"
                        },
                        "matched": {
                          "type": "integer"
                        },
                        "mismatch": {
                          "type": "integer"
                        },
                        "ambiguous": {
                          "type": "integer"
                        },
                        "not_found": {
                          "type": "integer"
                        },
                        "errored": {
                          "type": "integer"
                        },
                        "retracted": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "mixed": {
                    "summary": "One matched, one fabricated (mismatch)",
                    "value": {
                      "ok": true,
                      "format": "bibtex",
                      "entries": [
                        {
                          "index": 1,
                          "status": "ok",
                          "verdict": "matched",
                          "confidence": "high",
                          "matched": {
                            "title": "Fabricated citations: an audit across 2.5 million biomedical papers",
                            "DOI": "10.1016/S0140-6736(26)00603-3"
                          },
                          "mismatches": [],
                          "retraction": {
                            "checked": true,
                            "doi": "10.1016/S0140-6736(26)00603-3",
                            "isRetracted": false,
                            "hasCorrections": false,
                            "hasConcern": false,
                            "notices": []
                          },
                          "_provenance": {
                            "stages_run": [
                              "compare"
                            ],
                            "resolved_via": "crossref"
                          }
                        },
                        {
                          "index": 2,
                          "status": "ok",
                          "verdict": "mismatch",
                          "confidence": "high",
                          "matched": {
                            "title": "ChatGPT in Research: Balancing Ethics, Transparency and Advancement",
                            "DOI": "10.1016/j.neuroscience.2023.02.008"
                          },
                          "mismatches": [
                            {
                              "field": "title",
                              "claimed": "An invented title",
                              "resolved": "ChatGPT in Research: Balancing Ethics, Transparency and Advancement",
                              "similarity": 0.08
                            }
                          ],
                          "retraction": {
                            "checked": true,
                            "doi": "10.1016/j.neuroscience.2023.02.008",
                            "isRetracted": false,
                            "hasCorrections": false,
                            "hasConcern": false,
                            "notices": []
                          },
                          "_provenance": {
                            "stages_run": [
                              "compare",
                              "search"
                            ],
                            "resolved_via": "crossref"
                          }
                        }
                      ],
                      "parseErrors": [],
                      "truncated": 0,
                      "summary": {
                        "total": 2,
                        "matched": 1,
                        "mismatch": 1,
                        "ambiguous": 0,
                        "not_found": 0,
                        "errored": 0,
                        "retracted": 0
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Instructs clients not to cache.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "413": {
            "description": "Request body exceeds the maximum allowed size.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "502": {
            "description": "Total verification outage (every entry errored upstream — safe to retry).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/csl/styles": {
      "get": {
        "tags": [
          "Styles"
        ],
        "summary": "Discover CSL citation styles (searchable, paginated)",
        "description": "Search and browse available CSL styles — hand-tuned builtins, common\naliases, and (when `ENABLE_CSL_IMPORTS` is on) the remote CSL registry.\nResults are **offset-paginated** via `limit` and `offset`; the response\ncarries `total` (the full match count) alongside the applied\n`limit`/`offset` window.\n",
        "operationId": "cslStylesList",
        "parameters": [
          {
            "in": "header",
            "name": "Api-Version",
            "required": false,
            "description": "Optional API version selector (header-based versioning). The API\ncurrently serves a single version; the active version is returned on\nevery response in `X-Scholar-Transform-Version`. Reserved for forward\ncompatibility — when a future breaking version ships, clients pin to a\nversion with this header and retired versions follow the deprecation\npolicy described in the API overview.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          },
          {
            "in": "query",
            "name": "q",
            "required": false,
            "description": "Case-insensitive substring match against style id, title, and short title.",
            "schema": {
              "type": "string"
            },
            "example": "chicago"
          },
          {
            "in": "query",
            "name": "category",
            "required": false,
            "description": "Filter to styles whose categories include this token.",
            "schema": {
              "type": "string"
            },
            "example": "medicine"
          },
          {
            "in": "query",
            "name": "bundled",
            "required": false,
            "description": "When `true`, return only hand-tuned builtin styles (no aliases or remote).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "description": "Page size. Defaults to 50; clamped to 20000. Use `0` to return all matches.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 20000,
              "default": 50
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "description": "Zero-based start offset into the matched set.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "in": "query",
            "name": "remote",
            "required": false,
            "description": "Set to `0` to exclude remote-registry styles even when imports are enabled.",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ]
            }
          },
          {
            "in": "query",
            "name": "categories",
            "required": false,
            "description": "Set to `1` to include available category facets in the response.",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of matching CSL styles.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Transform-Version": {
                "description": "Public, monotonically-versioned tag for normalisation + formatting\nlogic — returned on every response. Serves as the active API version\nunder the header-based versioning scheme.\n",
                "schema": {
                  "type": "string",
                  "example": "2026-08-18"
                }
              },
              "Cache-Control": {
                "description": "Public cache hint for style discovery.",
                "schema": {
                  "type": "string",
                  "example": "public, max-age=3600"
                }
              },
              "Link": {
                "description": "RFC 8288 link header. Present only when more results exist; carries\nthe next-page URL with `rel=\"next\"`.\n",
                "schema": {
                  "type": "string",
                  "example": "</api/csl/styles?q=chicago&offset=50&limit=50>; rel=\"next\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Paginated CSL style discovery result. Pagination is offset-based:\n`total` is the full match count; `limit`/`offset` echo the applied\nwindow (`limit: 0` returns all matches).\n",
                  "required": [
                    "ok",
                    "styles",
                    "total",
                    "limit",
                    "offset"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "styles": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "description": "A single CSL style entry returned by style discovery.",
                        "required": [
                          "id",
                          "title",
                          "bundled"
                        ],
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "vancouver"
                          },
                          "title": {
                            "type": "string",
                            "example": "Vancouver"
                          },
                          "titleShort": {
                            "type": "string",
                            "example": "APA"
                          },
                          "categories": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "example": [
                              "medicine",
                              "numeric"
                            ]
                          },
                          "bundled": {
                            "type": "boolean",
                            "description": "True for hand-tuned builtin styles shipped with the API."
                          },
                          "engineSupported": {
                            "type": "boolean",
                            "description": "True when the CSL engine can render the style directly."
                          },
                          "aliasFor": {
                            "type": "string",
                            "description": "Present on alias entries — the style this alias resolves to.",
                            "example": "apa"
                          }
                        }
                      }
                    },
                    "total": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Total number of styles matching the query, before pagination."
                    },
                    "limit": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Applied page size (0 means \"all matches\", no windowing)."
                    },
                    "offset": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Applied start offset into the matched set."
                    },
                    "nextOffset": {
                      "description": "Explicit continuation token — the `offset` to request for the next\npage, or `null` on the last page (or when `limit: 0` returned all\nmatches). When non-null, an RFC 8288 `Link: <…>; rel=\"next\"` response\nheader carries the same next-page URL.\n",
                      "type": "integer",
                      "minimum": 0,
                      "nullable": true
                    },
                    "importsEnabled": {
                      "type": "boolean",
                      "description": "Whether remote CSL imports are enabled for this deployment."
                    },
                    "categories": {
                      "type": "object",
                      "description": "Present only when `?categories=1`. Available category facets.",
                      "properties": {
                        "all": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "bundled": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "remote": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "bundledCount": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "aliasCount": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "note": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "total": 2,
                  "limit": 50,
                  "offset": 0,
                  "nextOffset": null,
                  "importsEnabled": false,
                  "styles": [
                    {
                      "id": "vancouver",
                      "title": "Vancouver",
                      "categories": [
                        "medicine",
                        "science",
                        "numeric"
                      ],
                      "bundled": true,
                      "engineSupported": true
                    },
                    {
                      "id": "harvard",
                      "title": "Harvard style (uses APA formatting)",
                      "categories": [],
                      "bundled": false,
                      "engineSupported": true,
                      "aliasFor": "apa"
                    }
                  ],
                  "meta": {
                    "bundledCount": 10,
                    "aliasCount": 3,
                    "note": "Only bundled styles are available. Set ENABLE_CSL_IMPORTS=1 to enable remote styles."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the window resets.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset-After": {
                "description": "Seconds until reset.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Policy": {
                "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until next request allowed.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily unavailable (maintenance mode).",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Scholar-Mode": {
                "description": "Effective service mode (normal, read-only, maintenance).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "normal",
                    "read-only",
                    "maintenance"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          },
          "default": {
            "description": "Typed error (catch-all). Body is the shared `ErrorResponse` envelope and\nthe stable code is mirrored in the `X-Error-Code` response header.\n",
            "headers": {
              "X-Request-Id": {
                "description": "Unique request correlation ID.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Error-Code": {
                "description": "Stable internal error code.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "ok",
                    "code",
                    "error"
                  ],
                  "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                    }
                  },
                  "example": {
                    "ok": false,
                    "code": "BAD_REQUEST",
                    "error": "Invalid input"
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
                  "required": [
                    "type",
                    "title",
                    "status",
                    "code"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "format": "uri",
                      "description": "A URI identifying the problem type (per stable error code).",
                      "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                    },
                    "title": {
                      "type": "string",
                      "description": "Short, human-readable summary of the problem type.",
                      "example": "Validation Error"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code (duplicated from the response line).",
                      "example": 400
                    },
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation specific to this occurrence.",
                      "example": "Missing 'lines' (array) or 'text' (string) in body."
                    },
                    "instance": {
                      "type": "string",
                      "description": "Optional request correlation id (mirrors X-Request-Id)."
                    },
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                      "example": "VALIDATION_ERROR"
                    }
                  },
                  "example": {
                    "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                    "title": "Validation Error",
                    "status": 400,
                    "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                    "code": "VALIDATION_ERROR"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "ssk_",
        "description": "First-party Scholar Sidekick API key (prefixed `ssk_`). Create one at https://scholar-sidekick.com/account and send it as `Authorization: Bearer ssk_…`. Signed-in keys get a higher rate-limit tier than anonymous access."
      },
      "RapidApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-RapidAPI-Key",
        "description": "RapidAPI marketplace key forwarded by RapidAPI gateway (paid/managed tiers)."
      }
    },
    "schemas": {
      "StreamEvent": {
        "type": "object",
        "description": "A single newline-delimited JSON event from `POST /api/format/stream`.\n`type` discriminates the event; `idx` is the 0-based item index (or `-1`\nfor stream-level events). The stream opens with `start` and ends with `done`.\n",
        "required": [
          "type",
          "idx"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "start",
              "item",
              "error",
              "skip-duplicate",
              "warning",
              "done"
            ]
          },
          "idx": {
            "type": "integer",
            "description": "Item index, or -1 for stream-level events."
          },
          "render": {
            "type": "string",
            "description": "Rendered citation (builtin formatter `item` events)."
          },
          "message": {
            "type": "string",
            "description": "Human-readable text (`error` / `warning` events)."
          },
          "code": {
            "type": "string",
            "description": "Stable error code (`error` events)."
          },
          "output": {
            "type": "string",
            "description": "Full rendered output (terminal `done` event)."
          },
          "formatter": {
            "type": "string",
            "enum": [
              "builtin",
              "csl"
            ]
          },
          "styleUsed": {
            "type": "string"
          },
          "afterDedupe": {
            "type": "integer"
          },
          "meta": {
            "allOf": [
              {
                "type": "object",
                "additionalProperties": true,
                "description": "Phase 12b batch summary. Aggregate counts + a duplicate-group list for a\nrequest. Additive metadata only — it never changes the formatted output.\n`resolved` counts input lines that mapped to a work, so the buckets are\nself-consistent: `linesIn === resolved + notFound + errored + skipped`,\nand `duplicates === resolved - afterDedupe`. The same shape appears on the\nstream `done` frame. Error/skip buckets are best-effort and may differ\nslightly between /api/format (dedups failing lines) and\n/api/format/stream (counts them per occurrence).\n",
                "properties": {
                  "linesIn": {
                    "type": "integer",
                    "description": "Total input lines."
                  },
                  "resolved": {
                    "type": "integer",
                    "description": "Input lines that resolved to a work."
                  },
                  "afterDedupe": {
                    "type": "integer",
                    "description": "Distinct works after de-duplication."
                  },
                  "duplicates": {
                    "type": "integer",
                    "description": "Collapsed duplicate lines (resolved - afterDedupe)."
                  },
                  "notFound": {
                    "type": "integer",
                    "description": "Lines that resolved to no record."
                  },
                  "errored": {
                    "type": "integer",
                    "description": "Lines that failed on an upstream/other error."
                  },
                  "skipped": {
                    "type": "integer",
                    "description": "ISSN-container / ADS-without-token lines skipped."
                  },
                  "warned": {
                    "type": "integer",
                    "description": "Count of batch warning strings."
                  },
                  "duplicateGroups": {
                    "type": "array",
                    "description": "One entry per item whose input lines collapsed (>1 source line).",
                    "items": {
                      "type": "object",
                      "properties": {
                        "idx": {
                          "type": "integer",
                          "description": "First contributing input-line index."
                        },
                        "sourceIdxs": {
                          "type": "array",
                          "items": {
                            "type": "integer"
                          },
                          "description": "All input-line indices that collapsed into this item."
                        }
                      }
                    }
                  }
                }
              }
            ],
            "description": "Batch summary on the terminal `done` event (same shape as /api/format `meta`)."
          }
        }
      },
      "CslStylesResponse": {
        "type": "object",
        "description": "Paginated CSL style discovery result. Pagination is offset-based:\n`total` is the full match count; `limit`/`offset` echo the applied\nwindow (`limit: 0` returns all matches).\n",
        "required": [
          "ok",
          "styles",
          "total",
          "limit",
          "offset"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "styles": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "A single CSL style entry returned by style discovery.",
              "required": [
                "id",
                "title",
                "bundled"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "example": "vancouver"
                },
                "title": {
                  "type": "string",
                  "example": "Vancouver"
                },
                "titleShort": {
                  "type": "string",
                  "example": "APA"
                },
                "categories": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "example": [
                    "medicine",
                    "numeric"
                  ]
                },
                "bundled": {
                  "type": "boolean",
                  "description": "True for hand-tuned builtin styles shipped with the API."
                },
                "engineSupported": {
                  "type": "boolean",
                  "description": "True when the CSL engine can render the style directly."
                },
                "aliasFor": {
                  "type": "string",
                  "description": "Present on alias entries — the style this alias resolves to.",
                  "example": "apa"
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total number of styles matching the query, before pagination."
          },
          "limit": {
            "type": "integer",
            "minimum": 0,
            "description": "Applied page size (0 means \"all matches\", no windowing)."
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "description": "Applied start offset into the matched set."
          },
          "nextOffset": {
            "description": "Explicit continuation token — the `offset` to request for the next\npage, or `null` on the last page (or when `limit: 0` returned all\nmatches). When non-null, an RFC 8288 `Link: <…>; rel=\"next\"` response\nheader carries the same next-page URL.\n",
            "type": "integer",
            "minimum": 0,
            "nullable": true
          },
          "importsEnabled": {
            "type": "boolean",
            "description": "Whether remote CSL imports are enabled for this deployment."
          },
          "categories": {
            "type": "object",
            "description": "Present only when `?categories=1`. Available category facets.",
            "properties": {
              "all": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "bundled": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "remote": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "bundledCount": {
                "type": "integer",
                "minimum": 0
              },
              "aliasCount": {
                "type": "integer",
                "minimum": 0
              },
              "note": {
                "type": "string"
              }
            }
          }
        }
      },
      "FormatRequest": {
        "description": "Batch-capable. Provide either `text` (free text containing one or more\nidentifiers, one per line) or `lines` (an array of identifiers); both\nresolve and format every identifier in a single call. Bounded by a\n128 KB request body and a maximum of 500 identifiers per request.\n",
        "oneOf": [
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "text"
            ],
            "properties": {
              "text": {
                "type": "string",
                "description": "Free text with one or more identifiers, one per line (batch input)."
              },
              "style": {
                "type": "string",
                "maxLength": 64,
                "description": "Citation style id — a builtin name or a CSL style id."
              },
              "lang": {
                "type": "string",
                "maxLength": 16,
                "default": "en-US",
                "description": "BCP-47 locale for the rendered citation."
              },
              "locale": {
                "type": "string",
                "maxLength": 16,
                "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
              },
              "footnote": {
                "type": "boolean",
                "default": false,
                "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
              },
              "output": {
                "type": "string",
                "enum": [
                  "text",
                  "html",
                  "json"
                ],
                "default": "text",
                "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
              },
              "nocache": {
                "type": "boolean",
                "default": false,
                "description": "Bypass the resolver cache for this request."
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "lines"
            ],
            "properties": {
              "lines": {
                "type": "array",
                "description": "Batch input: identifiers to resolve and format, one per element.",
                "minItems": 1,
                "maxItems": 500,
                "items": {
                  "type": "string"
                }
              },
              "style": {
                "type": "string",
                "maxLength": 64,
                "description": "Citation style id — a builtin name or a CSL style id."
              },
              "lang": {
                "type": "string",
                "maxLength": 16,
                "default": "en-US",
                "description": "BCP-47 locale for the rendered citation."
              },
              "locale": {
                "type": "string",
                "maxLength": 16,
                "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
              },
              "footnote": {
                "type": "boolean",
                "default": false,
                "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
              },
              "output": {
                "type": "string",
                "enum": [
                  "text",
                  "html",
                  "json"
                ],
                "default": "text",
                "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
              },
              "nocache": {
                "type": "boolean",
                "default": false,
                "description": "Bypass the resolver cache for this request."
              }
            }
          }
        ]
      },
      "FormatItemsRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "items"
        ],
        "description": "Batch-capable: formats up to 500 pre-parsed CSL-JSON items in one call.\n",
        "properties": {
          "items": {
            "type": "array",
            "description": "Batch input: pre-parsed CSL-JSON items, one per element.",
            "minItems": 1,
            "maxItems": 500,
            "items": {
              "type": "object",
              "description": "CSL-JSON item"
            }
          },
          "style": {
            "type": "string",
            "maxLength": 64,
            "description": "Citation style id — a builtin name or a CSL style id."
          },
          "lang": {
            "type": "string",
            "maxLength": 16,
            "default": "en-US",
            "description": "BCP-47 locale for the rendered citation."
          },
          "locale": {
            "type": "string",
            "maxLength": 16,
            "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
          },
          "footnote": {
            "type": "boolean",
            "default": false,
            "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
          },
          "output": {
            "type": "string",
            "enum": [
              "text",
              "html",
              "json"
            ],
            "default": "text",
            "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
          },
          "nocache": {
            "type": "boolean",
            "default": false,
            "description": "Bypass the resolver cache for this request."
          }
        }
      },
      "ExportRequest": {
        "description": "Batch-capable. Provide `text` (one or more identifiers, one per line) or\n`items` (pre-parsed CSL-JSON); exports all entries into a single file.\nBounded by a 128 KB request body and a maximum of 500 items per request.\n",
        "oneOf": [
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "text",
              "format"
            ],
            "properties": {
              "text": {
                "type": "string",
                "description": "Free text with one or more identifiers, one per line (batch input)."
              },
              "style": {
                "type": "string",
                "maxLength": 64,
                "description": "Citation style id — a builtin name or a CSL style id."
              },
              "lang": {
                "type": "string",
                "maxLength": 16,
                "default": "en-US",
                "description": "BCP-47 locale for the rendered citation."
              },
              "locale": {
                "type": "string",
                "maxLength": 16,
                "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
              },
              "footnote": {
                "type": "boolean",
                "default": false,
                "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
              },
              "output": {
                "type": "string",
                "enum": [
                  "text",
                  "html",
                  "json"
                ],
                "default": "text",
                "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
              },
              "nocache": {
                "type": "boolean",
                "default": false,
                "description": "Bypass the resolver cache for this request."
              },
              "format": {
                "type": "string",
                "description": "Export format. The route additionally accepts the internal\nspellings `bib`, `csl`, `medline` and `zotero-rdf`; the names\npublished here are the ecosystem-standard equivalents.\n",
                "enum": [
                  "txt",
                  "ris",
                  "bibtex",
                  "csl-json",
                  "endnote-xml",
                  "endnote-refer",
                  "refworks",
                  "nbib",
                  "rdf",
                  "csv"
                ]
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "items",
              "format"
            ],
            "properties": {
              "items": {
                "type": "array",
                "description": "Batch input: pre-parsed CSL-JSON items to export, one per element.",
                "minItems": 1,
                "maxItems": 500,
                "items": {
                  "type": "object",
                  "description": "CSL-JSON item"
                }
              },
              "style": {
                "type": "string",
                "maxLength": 64,
                "description": "Citation style id — a builtin name or a CSL style id."
              },
              "lang": {
                "type": "string",
                "maxLength": 16,
                "default": "en-US",
                "description": "BCP-47 locale for the rendered citation."
              },
              "locale": {
                "type": "string",
                "maxLength": 16,
                "description": "Accepted alias for `lang`. When both are sent, `lang` wins."
              },
              "footnote": {
                "type": "boolean",
                "default": false,
                "description": "Render note form instead of a bibliography entry.\n\n⚠️ **Honoured only when the request resolves to the CSL engine**\n(`formatter: \"csl\"` — an alias, dependent or resolved style). The five\nbuiltin styles (`vancouver`/`ama`/`apa`/`ieee`/`cse`) have no note form,\nso the flag is **silently downgraded** and the response echoes\n`footnote: false`. The downgrade is reported honestly in the body but\nraises no warning header.\n"
              },
              "output": {
                "type": "string",
                "enum": [
                  "text",
                  "html",
                  "json"
                ],
                "default": "text",
                "description": "Output mode.\n\n⚠️ `html` is **CSL path only**, on the same rule as `footnote`: on a\nbuiltin style the response reports `outputMode: \"text\"`. Note that both\n`text` and `html` are populated in the response regardless of\n`outputMode`, so builtin callers still get an HTML rendering.\n"
              },
              "nocache": {
                "type": "boolean",
                "default": false,
                "description": "Bypass the resolver cache for this request."
              },
              "format": {
                "type": "string",
                "enum": [
                  "txt",
                  "ris",
                  "bibtex",
                  "csl-json",
                  "endnote-xml",
                  "endnote-refer",
                  "refworks",
                  "nbib",
                  "rdf",
                  "csv"
                ]
              }
            }
          }
        ]
      },
      "VerifyClaim": {
        "type": "object",
        "additionalProperties": false,
        "description": "Caller-supplied citation under verification. `title` is required (a\nmissing title returns `400 MISSING_TITLE`). An identifier is optional;\nwith none, the verifier title-searches when the title is specific\nenough, otherwise returns `not_found` with\n`_provenance.skipped_reason: \"insufficient_claim\"`.\n",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          "authors": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "family"
              ],
              "properties": {
                "family": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "given": {
                  "type": "string",
                  "maxLength": 200
                }
              }
            }
          },
          "year": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9999
          },
          "container": {
            "type": "string",
            "maxLength": 500
          },
          "doi": {
            "type": "string",
            "maxLength": 200
          },
          "pmid": {
            "type": "string",
            "maxLength": 50
          },
          "pmcid": {
            "type": "string",
            "maxLength": 50
          },
          "isbn": {
            "type": "string",
            "maxLength": 50
          },
          "arxiv": {
            "type": "string",
            "maxLength": 50
          },
          "issn": {
            "type": "string",
            "maxLength": 50
          },
          "ads": {
            "type": "string",
            "maxLength": 50
          },
          "whoIrisUrl": {
            "type": "string",
            "maxLength": 2000
          }
        }
      },
      "VerifyRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "claimed"
        ],
        "properties": {
          "claimed": {
            "type": "object",
            "additionalProperties": false,
            "description": "Caller-supplied citation under verification. `title` is required (a\nmissing title returns `400 MISSING_TITLE`). An identifier is optional;\nwith none, the verifier title-searches when the title is specific\nenough, otherwise returns `not_found` with\n`_provenance.skipped_reason: \"insufficient_claim\"`.\n",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "maxLength": 2000
              },
              "authors": {
                "type": "array",
                "maxItems": 50,
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "family"
                  ],
                  "properties": {
                    "family": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    "given": {
                      "type": "string",
                      "maxLength": 200
                    }
                  }
                }
              },
              "year": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9999
              },
              "container": {
                "type": "string",
                "maxLength": 500
              },
              "doi": {
                "type": "string",
                "maxLength": 200
              },
              "pmid": {
                "type": "string",
                "maxLength": 50
              },
              "pmcid": {
                "type": "string",
                "maxLength": 50
              },
              "isbn": {
                "type": "string",
                "maxLength": 50
              },
              "arxiv": {
                "type": "string",
                "maxLength": 50
              },
              "issn": {
                "type": "string",
                "maxLength": 50
              },
              "ads": {
                "type": "string",
                "maxLength": 50
              },
              "whoIrisUrl": {
                "type": "string",
                "maxLength": 2000
              }
            }
          },
          "options": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "bypassCache": {
                "type": "boolean"
              },
              "screen_with_llm": {
                "type": "boolean",
                "description": "Opt-in Stage 3 LLM screen (Phase 12i.3). Fires only when the\npre-LLM verdict is `mismatch` with `confidence: low` (the\ninformal-abbreviation false-positive bucket). Gated:\nauthenticated first-party callers and paid RapidAPI tiers\nonly. Anonymous / free callers receive `400\nLLM_SCREEN_FORBIDDEN`. Per-day budget cap is configurable\nvia `LLM_VERIFY_DAILY_BUDGET_USD` (default $5/day); when\nexceeded the request still returns its non-LLM verdict\nwith `_provenance.llm_screen.reason = daily_budget_exceeded`.\n"
              }
            }
          }
        }
      },
      "VerifyProvenance": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "stages_run",
          "resolved_via"
        ],
        "properties": {
          "stages_run": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "compare",
                "search",
                "llm_screen",
                "containment"
              ]
            }
          },
          "resolved_via": {
            "description": "Identifier of the resolver-source service (e.g., `crossref`, `pubmed`).",
            "type": "string",
            "nullable": true
          },
          "method": {
            "type": "string",
            "enum": [
              "compare",
              "containment"
            ],
            "description": "Which verdict method produced this entry. Absent (or `compare`) is the\ndefault single-citation path: a clean claimed title compared to the\nresolved title via full-string similarity. `containment` is the\nprose-reference path (`/api/audit` `references[]` input, e.g. a `.docx`\nupload): no clean title is available, so the resolved title is checked\nfor token-containment within the raw reference text.\n"
          },
          "containment": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "score",
              "matched_tokens",
              "total_tokens"
            ],
            "description": "Containment scoring detail — present only on containment-method entries.",
            "properties": {
              "score": {
                "type": "number",
                "description": "Fraction (0-1) of the resolved title's significant tokens found in the reference text."
              },
              "matched_tokens": {
                "type": "integer"
              },
              "total_tokens": {
                "type": "integer"
              },
              "corroboration": {
                "type": "string",
                "enum": [
                  "corroborated",
                  "refuted",
                  "partial",
                  "unavailable"
                ],
                "description": "Author+year second signal, used to disambiguate a LOW title score —\na translated or reworded genuine citation and a fabricated title\nboth score near zero on title tokens alone, but author surnames\nand the year are language-invariant.\n- `corroborated`: the resolved record's author AND year appear in\n  the reference, so the citation points at this work however the\n  title was written. The entry is rescued to `ambiguous` (review)\n  and never flagged as a fabrication; a caveat explains why.\n- `refuted`: the record has a usable surname and a year and\n  NEITHER appears, so two independent signals agree — a wider\n  mismatch cutoff applies.\n- `partial`: exactly one of the two appears. That is not\n  disagreement — a genuine citation that omits the year, or\n  romanises an author differently (\"Mueller\" vs \"Müller\"), trips\n  this — so the conservative cutoff applies.\n- `unavailable`: the record carries no usable surname or no year,\n  so there is nothing to corroborate with; the conservative\n  near-zero-overlap cutoff applies.\n"
              }
            }
          },
          "v1_limitations": {
            "type": "array",
            "deprecated": true,
            "items": {
              "type": "string"
            },
            "description": "Deprecated since 12i.2 and never emitted by the current route.\nPre-12i.2 the verifier emitted `no_identifier_provided_in_v1` here\nwhen the claim lacked an identifier; the active title-search path\nreplaced that case. Superseded by `caveats`.\n"
          },
          "caveats": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Point-of-use limitations of this verdict (SPEC §10). Each string is\nemitted only when deterministically TRUE of the comparison — e.g.\n`\"resolved via title-search; the supplied identifier did not\nresolve\"`, `\"container-only identifier (ISSN); verifies the journal,\nnot a specific work\"`, `\"title is non-Latin script; character-level\nsimilarity is weaker here\"`, `\"verdict reflects a publication-year\ngap\"`, `\"group author could not be cross-checked against the\nrecord\"`, `\"a claimed co-author could not be found on the resolved\nrecord\"`, `\"no record found in the scholarly registries searched;\nsources outside them (standards, software repositories, model cards,\ninstitutional reports) are not indexed here\"`. Absent (not an empty\narray) on a clean high-confidence `matched`.\n"
          },
          "skipped_reason": {
            "type": "string",
            "enum": [
              "insufficient_claim",
              "container_only",
              "no_identifier",
              "sparse_resolved_title"
            ],
            "description": "Present when the verifier short-circuited before searching. Verdict is\n`not_found` in these cases; absent on normal verdicts.\n- `insufficient_claim`: the claim carried no identifier and a title too\n  sparse to title-search safely (e.g. a single token).\n- `container_only`: the identifier resolved to a journal/container\n  (e.g. an ISSN), not a work — there is no paper to verify (Phase 12j).\n- `no_identifier`: (containment path) the reference text carried no\n  detectable identifier, so there was nothing to resolve against.\n- `sparse_resolved_title`: (containment path) the identifier resolved,\n  but the record's title is too short to score containment safely.\n"
          },
          "registries_searched": {
            "type": "array",
            "description": "Per-registry status block surfaced when the title-search\naggregator ran. Absent on the compare-only fast path.\n",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "registry",
                "ok",
                "count"
              ],
              "properties": {
                "registry": {
                  "type": "string",
                  "enum": [
                    "crossref",
                    "pubmed",
                    "openalex"
                  ]
                },
                "ok": {
                  "type": "boolean"
                },
                "count": {
                  "type": "integer",
                  "minimum": 0
                },
                "reason": {
                  "type": "string",
                  "description": "Failure reason (e.g., `upstream_error`, `invalid_input`) when\nthe registry adapter did not return results.\n"
                }
              }
            }
          },
          "llm_screen": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "applied"
            ],
            "description": "LLM screen telemetry (Phase 12i.3). Emitted on the response\nenvelope whenever the caller passed `options.screen_with_llm:\ntrue`. `applied: true` means a model call ran and produced a\nstructured verdict; `applied: false` carries a `reason` field\nexplaining why the screen was skipped.\n",
            "properties": {
              "applied": {
                "type": "boolean"
              },
              "model": {
                "type": "string",
                "description": "Model slug used for the screen (e.g., `anthropic/claude-haiku-4.5`)."
              },
              "prompt_version": {
                "type": "string",
                "description": "Prompt revision identifier — bumped with `SCHOLAR_VERIFY_VERSION`."
              },
              "verdict": {
                "type": "string",
                "enum": [
                  "informal_abbreviation",
                  "different_paper",
                  "uncertain"
                ],
                "description": "LLM classification. `informal_abbreviation` upgrades the\nverdict to `matched / low`; `different_paper` keeps `mismatch`\nand raises confidence to `high`; `uncertain` leaves the\npre-LLM verdict unchanged.\n"
              },
              "reasoning": {
                "type": "string",
                "description": "Justification (≤2000 chars) emitted alongside the verdict."
              },
              "cost_usd": {
                "type": "number",
                "minimum": 0,
                "description": "Approximate USD cost of the model call, computed from token\nusage and published list prices. Used by the daily-budget\nguard at `LLM_VERIFY_DAILY_BUDGET_USD`.\n"
              },
              "reason": {
                "type": "string",
                "enum": [
                  "verdict_not_eligible",
                  "daily_budget_exceeded",
                  "no_gateway",
                  "upstream_error",
                  "malformed_response"
                ],
                "description": "Set when `applied: false`. `verdict_not_eligible` means the\npre-LLM verdict was not `mismatch / low` so no model call was\nattempted.\n"
              }
            }
          }
        }
      },
      "VerifySuccessBody": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "verdict",
          "confidence",
          "matched",
          "mismatches",
          "_provenance"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "verdict": {
            "type": "string",
            "enum": [
              "matched",
              "mismatch",
              "not_found",
              "ambiguous"
            ]
          },
          "confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "matched": {
            "description": "Best record the verifier matched the claim to (resolver record\non the identifier path, or top search candidate on the no-id\npath). `null` when nothing meaningful matched.\n",
            "type": "object",
            "nullable": true
          },
          "mismatches": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "field",
                "similarity"
              ],
              "properties": {
                "field": {
                  "type": "string",
                  "enum": [
                    "title",
                    "first_author",
                    "year",
                    "container",
                    "coauthor"
                  ],
                  "description": "Which field disagreed. `coauthor` rows are emitted only when the\nco-author cross-check is enabled server-side, one row per claimed\nco-author that matched no author on the resolved record; unlike the\nother fields they never drive a `mismatch` — they downgrade\n`matched` to `ambiguous` (review).\n"
                },
                "claimed": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    }
                  ]
                },
                "resolved": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    }
                  ]
                },
                "similarity": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                }
              }
            }
          },
          "candidates": {
            "type": "array",
            "description": "Title-search alternatives, ranked by similarity (best first).\nPresent whenever the search stage ran; absent on the compare-only\nfast path.\n",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "item",
                "registries",
                "score"
              ],
              "description": "A title-search alternative surfaced when the verifier cannot confirm\nthe supplied identifier matches the claimed metadata. Present on\nverdicts `matched` (no-identifier path), `ambiguous`, `mismatch`\n(post-12i.2), and `not_found` (post-12i.2).\n",
              "properties": {
                "item": {
                  "type": "object",
                  "description": "BiblioItem matching the claim's title via search."
                },
                "registries": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "crossref",
                      "pubmed",
                      "openalex"
                    ]
                  }
                },
                "score": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1,
                  "description": "Title similarity (0-1) against the claim."
                }
              }
            }
          },
          "_provenance": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "stages_run",
              "resolved_via"
            ],
            "properties": {
              "stages_run": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "compare",
                    "search",
                    "llm_screen",
                    "containment"
                  ]
                }
              },
              "resolved_via": {
                "description": "Identifier of the resolver-source service (e.g., `crossref`, `pubmed`).",
                "type": "string",
                "nullable": true
              },
              "method": {
                "type": "string",
                "enum": [
                  "compare",
                  "containment"
                ],
                "description": "Which verdict method produced this entry. Absent (or `compare`) is the\ndefault single-citation path: a clean claimed title compared to the\nresolved title via full-string similarity. `containment` is the\nprose-reference path (`/api/audit` `references[]` input, e.g. a `.docx`\nupload): no clean title is available, so the resolved title is checked\nfor token-containment within the raw reference text.\n"
              },
              "containment": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "score",
                  "matched_tokens",
                  "total_tokens"
                ],
                "description": "Containment scoring detail — present only on containment-method entries.",
                "properties": {
                  "score": {
                    "type": "number",
                    "description": "Fraction (0-1) of the resolved title's significant tokens found in the reference text."
                  },
                  "matched_tokens": {
                    "type": "integer"
                  },
                  "total_tokens": {
                    "type": "integer"
                  },
                  "corroboration": {
                    "type": "string",
                    "enum": [
                      "corroborated",
                      "refuted",
                      "partial",
                      "unavailable"
                    ],
                    "description": "Author+year second signal, used to disambiguate a LOW title score —\na translated or reworded genuine citation and a fabricated title\nboth score near zero on title tokens alone, but author surnames\nand the year are language-invariant.\n- `corroborated`: the resolved record's author AND year appear in\n  the reference, so the citation points at this work however the\n  title was written. The entry is rescued to `ambiguous` (review)\n  and never flagged as a fabrication; a caveat explains why.\n- `refuted`: the record has a usable surname and a year and\n  NEITHER appears, so two independent signals agree — a wider\n  mismatch cutoff applies.\n- `partial`: exactly one of the two appears. That is not\n  disagreement — a genuine citation that omits the year, or\n  romanises an author differently (\"Mueller\" vs \"Müller\"), trips\n  this — so the conservative cutoff applies.\n- `unavailable`: the record carries no usable surname or no year,\n  so there is nothing to corroborate with; the conservative\n  near-zero-overlap cutoff applies.\n"
                  }
                }
              },
              "v1_limitations": {
                "type": "array",
                "deprecated": true,
                "items": {
                  "type": "string"
                },
                "description": "Deprecated since 12i.2 and never emitted by the current route.\nPre-12i.2 the verifier emitted `no_identifier_provided_in_v1` here\nwhen the claim lacked an identifier; the active title-search path\nreplaced that case. Superseded by `caveats`.\n"
              },
              "caveats": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Point-of-use limitations of this verdict (SPEC §10). Each string is\nemitted only when deterministically TRUE of the comparison — e.g.\n`\"resolved via title-search; the supplied identifier did not\nresolve\"`, `\"container-only identifier (ISSN); verifies the journal,\nnot a specific work\"`, `\"title is non-Latin script; character-level\nsimilarity is weaker here\"`, `\"verdict reflects a publication-year\ngap\"`, `\"group author could not be cross-checked against the\nrecord\"`, `\"a claimed co-author could not be found on the resolved\nrecord\"`, `\"no record found in the scholarly registries searched;\nsources outside them (standards, software repositories, model cards,\ninstitutional reports) are not indexed here\"`. Absent (not an empty\narray) on a clean high-confidence `matched`.\n"
              },
              "skipped_reason": {
                "type": "string",
                "enum": [
                  "insufficient_claim",
                  "container_only",
                  "no_identifier",
                  "sparse_resolved_title"
                ],
                "description": "Present when the verifier short-circuited before searching. Verdict is\n`not_found` in these cases; absent on normal verdicts.\n- `insufficient_claim`: the claim carried no identifier and a title too\n  sparse to title-search safely (e.g. a single token).\n- `container_only`: the identifier resolved to a journal/container\n  (e.g. an ISSN), not a work — there is no paper to verify (Phase 12j).\n- `no_identifier`: (containment path) the reference text carried no\n  detectable identifier, so there was nothing to resolve against.\n- `sparse_resolved_title`: (containment path) the identifier resolved,\n  but the record's title is too short to score containment safely.\n"
              },
              "registries_searched": {
                "type": "array",
                "description": "Per-registry status block surfaced when the title-search\naggregator ran. Absent on the compare-only fast path.\n",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "registry",
                    "ok",
                    "count"
                  ],
                  "properties": {
                    "registry": {
                      "type": "string",
                      "enum": [
                        "crossref",
                        "pubmed",
                        "openalex"
                      ]
                    },
                    "ok": {
                      "type": "boolean"
                    },
                    "count": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "reason": {
                      "type": "string",
                      "description": "Failure reason (e.g., `upstream_error`, `invalid_input`) when\nthe registry adapter did not return results.\n"
                    }
                  }
                }
              },
              "llm_screen": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "applied"
                ],
                "description": "LLM screen telemetry (Phase 12i.3). Emitted on the response\nenvelope whenever the caller passed `options.screen_with_llm:\ntrue`. `applied: true` means a model call ran and produced a\nstructured verdict; `applied: false` carries a `reason` field\nexplaining why the screen was skipped.\n",
                "properties": {
                  "applied": {
                    "type": "boolean"
                  },
                  "model": {
                    "type": "string",
                    "description": "Model slug used for the screen (e.g., `anthropic/claude-haiku-4.5`)."
                  },
                  "prompt_version": {
                    "type": "string",
                    "description": "Prompt revision identifier — bumped with `SCHOLAR_VERIFY_VERSION`."
                  },
                  "verdict": {
                    "type": "string",
                    "enum": [
                      "informal_abbreviation",
                      "different_paper",
                      "uncertain"
                    ],
                    "description": "LLM classification. `informal_abbreviation` upgrades the\nverdict to `matched / low`; `different_paper` keeps `mismatch`\nand raises confidence to `high`; `uncertain` leaves the\npre-LLM verdict unchanged.\n"
                  },
                  "reasoning": {
                    "type": "string",
                    "description": "Justification (≤2000 chars) emitted alongside the verdict."
                  },
                  "cost_usd": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Approximate USD cost of the model call, computed from token\nusage and published list prices. Used by the daily-budget\nguard at `LLM_VERIFY_DAILY_BUDGET_USD`.\n"
                  },
                  "reason": {
                    "type": "string",
                    "enum": [
                      "verdict_not_eligible",
                      "daily_budget_exceeded",
                      "no_gateway",
                      "upstream_error",
                      "malformed_response"
                    ],
                    "description": "Set when `applied: false`. `verdict_not_eligible` means the\npre-LLM verdict was not `mismatch / low` so no model call was\nattempted.\n"
                  }
                }
              }
            }
          }
        }
      },
      "AuditClaim": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "title"
        ],
        "description": "A single pre-parsed citation for the `claims[]` path. `title` is required.",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          "authors": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "family"
              ],
              "properties": {
                "family": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "given": {
                  "type": "string",
                  "maxLength": 200
                }
              }
            }
          },
          "year": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9999
          },
          "container": {
            "type": "string",
            "maxLength": 500
          },
          "doi": {
            "type": "string",
            "maxLength": 200
          },
          "pmid": {
            "type": "string",
            "maxLength": 50
          },
          "pmcid": {
            "type": "string",
            "maxLength": 50
          },
          "isbn": {
            "type": "string",
            "maxLength": 50
          },
          "arxiv": {
            "type": "string",
            "maxLength": 50
          },
          "issn": {
            "type": "string",
            "maxLength": 50
          },
          "ads": {
            "type": "string",
            "maxLength": 50
          },
          "whoIrisUrl": {
            "type": "string",
            "maxLength": 2000
          }
        }
      },
      "AuditRequest": {
        "type": "object",
        "additionalProperties": false,
        "description": "Provide EXACTLY ONE of `bibliography` (raw text), `claims` (array), or\n`references` (array of raw reference strings).\n",
        "properties": {
          "bibliography": {
            "type": "string",
            "maxLength": 131072,
            "description": "Raw BibTeX / RIS / CSL-JSON text. Format is auto-detected unless `format` is set."
          },
          "format": {
            "type": "string",
            "enum": [
              "bibtex",
              "ris",
              "csl-json"
            ],
            "description": "Override format auto-detection for `bibliography`."
          },
          "claims": {
            "type": "array",
            "maxItems": 25,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "description": "A single pre-parsed citation for the `claims[]` path. `title` is required.",
              "properties": {
                "title": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 2000
                },
                "authors": {
                  "type": "array",
                  "maxItems": 50,
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "family"
                    ],
                    "properties": {
                      "family": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "given": {
                        "type": "string",
                        "maxLength": 200
                      }
                    }
                  }
                },
                "year": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 9999
                },
                "container": {
                  "type": "string",
                  "maxLength": 500
                },
                "doi": {
                  "type": "string",
                  "maxLength": 200
                },
                "pmid": {
                  "type": "string",
                  "maxLength": 50
                },
                "pmcid": {
                  "type": "string",
                  "maxLength": 50
                },
                "isbn": {
                  "type": "string",
                  "maxLength": 50
                },
                "arxiv": {
                  "type": "string",
                  "maxLength": 50
                },
                "issn": {
                  "type": "string",
                  "maxLength": 50
                },
                "ads": {
                  "type": "string",
                  "maxLength": 50
                },
                "whoIrisUrl": {
                  "type": "string",
                  "maxLength": 2000
                }
              }
            }
          },
          "references": {
            "type": "array",
            "maxItems": 25,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 5000
            },
            "description": "Raw prose reference paragraphs (e.g. extracted from a `.docx`\nmanuscript). Each is verified via the CONTAINMENT method: its\nidentifier is resolved and the resolved title is checked for\ntoken-containment in the reference text (no clean claimed title is\nparsed). Response entries carry `_provenance.method: \"containment\"`;\nthe `x-scholar-containment-version` header pins the method version.\n"
          },
          "options": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "bypassCache": {
                "type": "boolean"
              },
              "screen_with_llm": {
                "type": "boolean",
                "description": "Opt-in Stage 3 LLM screen per entry (same gating as /api/verify). Default false."
              },
              "checks": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "retraction"
                  ]
                },
                "description": "Per-entry enrichment checks. Default: [retraction]. Pass [] to skip."
              }
            }
          }
        }
      },
      "AuditRetraction": {
        "type": "object",
        "additionalProperties": false,
        "description": "Per-entry retraction status. `checked` is false when retraction was not\nrequested, the entry had no resolvable DOI, or an upstream error was\nswallowed. `null` when `checks` did not include `retraction`.\n",
        "required": [
          "checked",
          "doi",
          "isRetracted",
          "hasCorrections",
          "hasConcern",
          "notices"
        ],
        "properties": {
          "checked": {
            "type": "boolean"
          },
          "doi": {
            "type": "string",
            "nullable": true
          },
          "isRetracted": {
            "type": "boolean"
          },
          "hasCorrections": {
            "type": "boolean"
          },
          "hasConcern": {
            "type": "boolean"
          },
          "notices": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "type": "string",
                  "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                },
                "label": {
                  "type": "string"
                },
                "doi": {
                  "type": "string",
                  "nullable": true
                },
                "date": {
                  "type": "string",
                  "nullable": true
                },
                "source": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "AuditEntry": {
        "type": "object",
        "description": "One result per verifiable entry. `status: \"ok\"` carries a verdict;\n`status: \"error\"` marks a per-entry upstream failure (the batch is not\nfailed by one bad entry).\n",
        "required": [
          "index",
          "status"
        ],
        "properties": {
          "index": {
            "type": "integer",
            "description": "1-based position in the input batch."
          },
          "sourceKey": {
            "type": "string",
            "description": "BibTeX key / RIS record index / CSL-JSON id, when present."
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "error"
            ]
          },
          "error": {
            "type": "string",
            "description": "Present only on status=error."
          },
          "verdict": {
            "type": "string",
            "enum": [
              "matched",
              "mismatch",
              "not_found",
              "ambiguous"
            ]
          },
          "confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "matched": {
            "type": "object",
            "description": "Resolver-returned BiblioItem.",
            "nullable": true
          },
          "mismatches": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "field",
                "similarity"
              ],
              "properties": {
                "field": {
                  "type": "string",
                  "enum": [
                    "title",
                    "first_author",
                    "year",
                    "container",
                    "coauthor"
                  ],
                  "description": "Which field disagreed. `coauthor` rows are emitted only when the\nco-author cross-check is enabled server-side, one row per claimed\nco-author that matched no author on the resolved record; unlike the\nother fields they never drive a `mismatch` — they downgrade\n`matched` to `ambiguous` (review).\n"
                },
                "claimed": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    }
                  ]
                },
                "resolved": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    }
                  ]
                },
                "similarity": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                }
              }
            }
          },
          "candidates": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "item",
                "registries",
                "score"
              ],
              "description": "A title-search alternative surfaced when the verifier cannot confirm\nthe supplied identifier matches the claimed metadata. Present on\nverdicts `matched` (no-identifier path), `ambiguous`, `mismatch`\n(post-12i.2), and `not_found` (post-12i.2).\n",
              "properties": {
                "item": {
                  "type": "object",
                  "description": "BiblioItem matching the claim's title via search."
                },
                "registries": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "crossref",
                      "pubmed",
                      "openalex"
                    ]
                  }
                },
                "score": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1,
                  "description": "Title similarity (0-1) against the claim."
                }
              }
            }
          },
          "retraction": {
            "type": "object",
            "additionalProperties": false,
            "description": "Per-entry retraction status. `checked` is false when retraction was not\nrequested, the entry had no resolvable DOI, or an upstream error was\nswallowed. `null` when `checks` did not include `retraction`.\n",
            "required": [
              "checked",
              "doi",
              "isRetracted",
              "hasCorrections",
              "hasConcern",
              "notices"
            ],
            "properties": {
              "checked": {
                "type": "boolean"
              },
              "doi": {
                "type": "string",
                "nullable": true
              },
              "isRetracted": {
                "type": "boolean"
              },
              "hasCorrections": {
                "type": "boolean"
              },
              "hasConcern": {
                "type": "boolean"
              },
              "notices": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                    },
                    "label": {
                      "type": "string"
                    },
                    "doi": {
                      "type": "string",
                      "nullable": true
                    },
                    "date": {
                      "type": "string",
                      "nullable": true
                    },
                    "source": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            },
            "nullable": true
          },
          "_provenance": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "stages_run",
              "resolved_via"
            ],
            "properties": {
              "stages_run": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "compare",
                    "search",
                    "llm_screen",
                    "containment"
                  ]
                }
              },
              "resolved_via": {
                "description": "Identifier of the resolver-source service (e.g., `crossref`, `pubmed`).",
                "type": "string",
                "nullable": true
              },
              "method": {
                "type": "string",
                "enum": [
                  "compare",
                  "containment"
                ],
                "description": "Which verdict method produced this entry. Absent (or `compare`) is the\ndefault single-citation path: a clean claimed title compared to the\nresolved title via full-string similarity. `containment` is the\nprose-reference path (`/api/audit` `references[]` input, e.g. a `.docx`\nupload): no clean title is available, so the resolved title is checked\nfor token-containment within the raw reference text.\n"
              },
              "containment": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "score",
                  "matched_tokens",
                  "total_tokens"
                ],
                "description": "Containment scoring detail — present only on containment-method entries.",
                "properties": {
                  "score": {
                    "type": "number",
                    "description": "Fraction (0-1) of the resolved title's significant tokens found in the reference text."
                  },
                  "matched_tokens": {
                    "type": "integer"
                  },
                  "total_tokens": {
                    "type": "integer"
                  },
                  "corroboration": {
                    "type": "string",
                    "enum": [
                      "corroborated",
                      "refuted",
                      "partial",
                      "unavailable"
                    ],
                    "description": "Author+year second signal, used to disambiguate a LOW title score —\na translated or reworded genuine citation and a fabricated title\nboth score near zero on title tokens alone, but author surnames\nand the year are language-invariant.\n- `corroborated`: the resolved record's author AND year appear in\n  the reference, so the citation points at this work however the\n  title was written. The entry is rescued to `ambiguous` (review)\n  and never flagged as a fabrication; a caveat explains why.\n- `refuted`: the record has a usable surname and a year and\n  NEITHER appears, so two independent signals agree — a wider\n  mismatch cutoff applies.\n- `partial`: exactly one of the two appears. That is not\n  disagreement — a genuine citation that omits the year, or\n  romanises an author differently (\"Mueller\" vs \"Müller\"), trips\n  this — so the conservative cutoff applies.\n- `unavailable`: the record carries no usable surname or no year,\n  so there is nothing to corroborate with; the conservative\n  near-zero-overlap cutoff applies.\n"
                  }
                }
              },
              "v1_limitations": {
                "type": "array",
                "deprecated": true,
                "items": {
                  "type": "string"
                },
                "description": "Deprecated since 12i.2 and never emitted by the current route.\nPre-12i.2 the verifier emitted `no_identifier_provided_in_v1` here\nwhen the claim lacked an identifier; the active title-search path\nreplaced that case. Superseded by `caveats`.\n"
              },
              "caveats": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Point-of-use limitations of this verdict (SPEC §10). Each string is\nemitted only when deterministically TRUE of the comparison — e.g.\n`\"resolved via title-search; the supplied identifier did not\nresolve\"`, `\"container-only identifier (ISSN); verifies the journal,\nnot a specific work\"`, `\"title is non-Latin script; character-level\nsimilarity is weaker here\"`, `\"verdict reflects a publication-year\ngap\"`, `\"group author could not be cross-checked against the\nrecord\"`, `\"a claimed co-author could not be found on the resolved\nrecord\"`, `\"no record found in the scholarly registries searched;\nsources outside them (standards, software repositories, model cards,\ninstitutional reports) are not indexed here\"`. Absent (not an empty\narray) on a clean high-confidence `matched`.\n"
              },
              "skipped_reason": {
                "type": "string",
                "enum": [
                  "insufficient_claim",
                  "container_only",
                  "no_identifier",
                  "sparse_resolved_title"
                ],
                "description": "Present when the verifier short-circuited before searching. Verdict is\n`not_found` in these cases; absent on normal verdicts.\n- `insufficient_claim`: the claim carried no identifier and a title too\n  sparse to title-search safely (e.g. a single token).\n- `container_only`: the identifier resolved to a journal/container\n  (e.g. an ISSN), not a work — there is no paper to verify (Phase 12j).\n- `no_identifier`: (containment path) the reference text carried no\n  detectable identifier, so there was nothing to resolve against.\n- `sparse_resolved_title`: (containment path) the identifier resolved,\n  but the record's title is too short to score containment safely.\n"
              },
              "registries_searched": {
                "type": "array",
                "description": "Per-registry status block surfaced when the title-search\naggregator ran. Absent on the compare-only fast path.\n",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "registry",
                    "ok",
                    "count"
                  ],
                  "properties": {
                    "registry": {
                      "type": "string",
                      "enum": [
                        "crossref",
                        "pubmed",
                        "openalex"
                      ]
                    },
                    "ok": {
                      "type": "boolean"
                    },
                    "count": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "reason": {
                      "type": "string",
                      "description": "Failure reason (e.g., `upstream_error`, `invalid_input`) when\nthe registry adapter did not return results.\n"
                    }
                  }
                }
              },
              "llm_screen": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "applied"
                ],
                "description": "LLM screen telemetry (Phase 12i.3). Emitted on the response\nenvelope whenever the caller passed `options.screen_with_llm:\ntrue`. `applied: true` means a model call ran and produced a\nstructured verdict; `applied: false` carries a `reason` field\nexplaining why the screen was skipped.\n",
                "properties": {
                  "applied": {
                    "type": "boolean"
                  },
                  "model": {
                    "type": "string",
                    "description": "Model slug used for the screen (e.g., `anthropic/claude-haiku-4.5`)."
                  },
                  "prompt_version": {
                    "type": "string",
                    "description": "Prompt revision identifier — bumped with `SCHOLAR_VERIFY_VERSION`."
                  },
                  "verdict": {
                    "type": "string",
                    "enum": [
                      "informal_abbreviation",
                      "different_paper",
                      "uncertain"
                    ],
                    "description": "LLM classification. `informal_abbreviation` upgrades the\nverdict to `matched / low`; `different_paper` keeps `mismatch`\nand raises confidence to `high`; `uncertain` leaves the\npre-LLM verdict unchanged.\n"
                  },
                  "reasoning": {
                    "type": "string",
                    "description": "Justification (≤2000 chars) emitted alongside the verdict."
                  },
                  "cost_usd": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Approximate USD cost of the model call, computed from token\nusage and published list prices. Used by the daily-budget\nguard at `LLM_VERIFY_DAILY_BUDGET_USD`.\n"
                  },
                  "reason": {
                    "type": "string",
                    "enum": [
                      "verdict_not_eligible",
                      "daily_budget_exceeded",
                      "no_gateway",
                      "upstream_error",
                      "malformed_response"
                    ],
                    "description": "Set when `applied: false`. `verdict_not_eligible` means the\npre-LLM verdict was not `mismatch / low` so no model call was\nattempted.\n"
                  }
                }
              }
            }
          }
        }
      },
      "AuditSuccessBody": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "format",
          "entries",
          "parseErrors",
          "truncated",
          "summary"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "format": {
            "type": "string",
            "enum": [
              "bibtex",
              "ris",
              "csl-json",
              null
            ],
            "description": "Detected input format, or null for the claims[] path.",
            "nullable": true
          },
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One result per verifiable entry. `status: \"ok\"` carries a verdict;\n`status: \"error\"` marks a per-entry upstream failure (the batch is not\nfailed by one bad entry).\n",
              "required": [
                "index",
                "status"
              ],
              "properties": {
                "index": {
                  "type": "integer",
                  "description": "1-based position in the input batch."
                },
                "sourceKey": {
                  "type": "string",
                  "description": "BibTeX key / RIS record index / CSL-JSON id, when present."
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "ok",
                    "error"
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Present only on status=error."
                },
                "verdict": {
                  "type": "string",
                  "enum": [
                    "matched",
                    "mismatch",
                    "not_found",
                    "ambiguous"
                  ]
                },
                "confidence": {
                  "type": "string",
                  "enum": [
                    "high",
                    "medium",
                    "low"
                  ]
                },
                "matched": {
                  "type": "object",
                  "description": "Resolver-returned BiblioItem.",
                  "nullable": true
                },
                "mismatches": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "field",
                      "similarity"
                    ],
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "title",
                          "first_author",
                          "year",
                          "container",
                          "coauthor"
                        ],
                        "description": "Which field disagreed. `coauthor` rows are emitted only when the\nco-author cross-check is enabled server-side, one row per claimed\nco-author that matched no author on the resolved record; unlike the\nother fields they never drive a `mismatch` — they downgrade\n`matched` to `ambiguous` (review).\n"
                      },
                      "claimed": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "number"
                          }
                        ]
                      },
                      "resolved": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "number"
                          }
                        ]
                      },
                      "similarity": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      }
                    }
                  }
                },
                "candidates": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "item",
                      "registries",
                      "score"
                    ],
                    "description": "A title-search alternative surfaced when the verifier cannot confirm\nthe supplied identifier matches the claimed metadata. Present on\nverdicts `matched` (no-identifier path), `ambiguous`, `mismatch`\n(post-12i.2), and `not_found` (post-12i.2).\n",
                    "properties": {
                      "item": {
                        "type": "object",
                        "description": "BiblioItem matching the claim's title via search."
                      },
                      "registries": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "crossref",
                            "pubmed",
                            "openalex"
                          ]
                        }
                      },
                      "score": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1,
                        "description": "Title similarity (0-1) against the claim."
                      }
                    }
                  }
                },
                "retraction": {
                  "type": "object",
                  "additionalProperties": false,
                  "description": "Per-entry retraction status. `checked` is false when retraction was not\nrequested, the entry had no resolvable DOI, or an upstream error was\nswallowed. `null` when `checks` did not include `retraction`.\n",
                  "required": [
                    "checked",
                    "doi",
                    "isRetracted",
                    "hasCorrections",
                    "hasConcern",
                    "notices"
                  ],
                  "properties": {
                    "checked": {
                      "type": "boolean"
                    },
                    "doi": {
                      "type": "string",
                      "nullable": true
                    },
                    "isRetracted": {
                      "type": "boolean"
                    },
                    "hasCorrections": {
                      "type": "boolean"
                    },
                    "hasConcern": {
                      "type": "boolean"
                    },
                    "notices": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "type": {
                            "type": "string",
                            "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                          },
                          "label": {
                            "type": "string"
                          },
                          "doi": {
                            "type": "string",
                            "nullable": true
                          },
                          "date": {
                            "type": "string",
                            "nullable": true
                          },
                          "source": {
                            "type": "string",
                            "nullable": true
                          }
                        }
                      }
                    }
                  },
                  "nullable": true
                },
                "_provenance": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "stages_run",
                    "resolved_via"
                  ],
                  "properties": {
                    "stages_run": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "compare",
                          "search",
                          "llm_screen",
                          "containment"
                        ]
                      }
                    },
                    "resolved_via": {
                      "description": "Identifier of the resolver-source service (e.g., `crossref`, `pubmed`).",
                      "type": "string",
                      "nullable": true
                    },
                    "method": {
                      "type": "string",
                      "enum": [
                        "compare",
                        "containment"
                      ],
                      "description": "Which verdict method produced this entry. Absent (or `compare`) is the\ndefault single-citation path: a clean claimed title compared to the\nresolved title via full-string similarity. `containment` is the\nprose-reference path (`/api/audit` `references[]` input, e.g. a `.docx`\nupload): no clean title is available, so the resolved title is checked\nfor token-containment within the raw reference text.\n"
                    },
                    "containment": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "score",
                        "matched_tokens",
                        "total_tokens"
                      ],
                      "description": "Containment scoring detail — present only on containment-method entries.",
                      "properties": {
                        "score": {
                          "type": "number",
                          "description": "Fraction (0-1) of the resolved title's significant tokens found in the reference text."
                        },
                        "matched_tokens": {
                          "type": "integer"
                        },
                        "total_tokens": {
                          "type": "integer"
                        },
                        "corroboration": {
                          "type": "string",
                          "enum": [
                            "corroborated",
                            "refuted",
                            "partial",
                            "unavailable"
                          ],
                          "description": "Author+year second signal, used to disambiguate a LOW title score —\na translated or reworded genuine citation and a fabricated title\nboth score near zero on title tokens alone, but author surnames\nand the year are language-invariant.\n- `corroborated`: the resolved record's author AND year appear in\n  the reference, so the citation points at this work however the\n  title was written. The entry is rescued to `ambiguous` (review)\n  and never flagged as a fabrication; a caveat explains why.\n- `refuted`: the record has a usable surname and a year and\n  NEITHER appears, so two independent signals agree — a wider\n  mismatch cutoff applies.\n- `partial`: exactly one of the two appears. That is not\n  disagreement — a genuine citation that omits the year, or\n  romanises an author differently (\"Mueller\" vs \"Müller\"), trips\n  this — so the conservative cutoff applies.\n- `unavailable`: the record carries no usable surname or no year,\n  so there is nothing to corroborate with; the conservative\n  near-zero-overlap cutoff applies.\n"
                        }
                      }
                    },
                    "v1_limitations": {
                      "type": "array",
                      "deprecated": true,
                      "items": {
                        "type": "string"
                      },
                      "description": "Deprecated since 12i.2 and never emitted by the current route.\nPre-12i.2 the verifier emitted `no_identifier_provided_in_v1` here\nwhen the claim lacked an identifier; the active title-search path\nreplaced that case. Superseded by `caveats`.\n"
                    },
                    "caveats": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Point-of-use limitations of this verdict (SPEC §10). Each string is\nemitted only when deterministically TRUE of the comparison — e.g.\n`\"resolved via title-search; the supplied identifier did not\nresolve\"`, `\"container-only identifier (ISSN); verifies the journal,\nnot a specific work\"`, `\"title is non-Latin script; character-level\nsimilarity is weaker here\"`, `\"verdict reflects a publication-year\ngap\"`, `\"group author could not be cross-checked against the\nrecord\"`, `\"a claimed co-author could not be found on the resolved\nrecord\"`, `\"no record found in the scholarly registries searched;\nsources outside them (standards, software repositories, model cards,\ninstitutional reports) are not indexed here\"`. Absent (not an empty\narray) on a clean high-confidence `matched`.\n"
                    },
                    "skipped_reason": {
                      "type": "string",
                      "enum": [
                        "insufficient_claim",
                        "container_only",
                        "no_identifier",
                        "sparse_resolved_title"
                      ],
                      "description": "Present when the verifier short-circuited before searching. Verdict is\n`not_found` in these cases; absent on normal verdicts.\n- `insufficient_claim`: the claim carried no identifier and a title too\n  sparse to title-search safely (e.g. a single token).\n- `container_only`: the identifier resolved to a journal/container\n  (e.g. an ISSN), not a work — there is no paper to verify (Phase 12j).\n- `no_identifier`: (containment path) the reference text carried no\n  detectable identifier, so there was nothing to resolve against.\n- `sparse_resolved_title`: (containment path) the identifier resolved,\n  but the record's title is too short to score containment safely.\n"
                    },
                    "registries_searched": {
                      "type": "array",
                      "description": "Per-registry status block surfaced when the title-search\naggregator ran. Absent on the compare-only fast path.\n",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "registry",
                          "ok",
                          "count"
                        ],
                        "properties": {
                          "registry": {
                            "type": "string",
                            "enum": [
                              "crossref",
                              "pubmed",
                              "openalex"
                            ]
                          },
                          "ok": {
                            "type": "boolean"
                          },
                          "count": {
                            "type": "integer",
                            "minimum": 0
                          },
                          "reason": {
                            "type": "string",
                            "description": "Failure reason (e.g., `upstream_error`, `invalid_input`) when\nthe registry adapter did not return results.\n"
                          }
                        }
                      }
                    },
                    "llm_screen": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "applied"
                      ],
                      "description": "LLM screen telemetry (Phase 12i.3). Emitted on the response\nenvelope whenever the caller passed `options.screen_with_llm:\ntrue`. `applied: true` means a model call ran and produced a\nstructured verdict; `applied: false` carries a `reason` field\nexplaining why the screen was skipped.\n",
                      "properties": {
                        "applied": {
                          "type": "boolean"
                        },
                        "model": {
                          "type": "string",
                          "description": "Model slug used for the screen (e.g., `anthropic/claude-haiku-4.5`)."
                        },
                        "prompt_version": {
                          "type": "string",
                          "description": "Prompt revision identifier — bumped with `SCHOLAR_VERIFY_VERSION`."
                        },
                        "verdict": {
                          "type": "string",
                          "enum": [
                            "informal_abbreviation",
                            "different_paper",
                            "uncertain"
                          ],
                          "description": "LLM classification. `informal_abbreviation` upgrades the\nverdict to `matched / low`; `different_paper` keeps `mismatch`\nand raises confidence to `high`; `uncertain` leaves the\npre-LLM verdict unchanged.\n"
                        },
                        "reasoning": {
                          "type": "string",
                          "description": "Justification (≤2000 chars) emitted alongside the verdict."
                        },
                        "cost_usd": {
                          "type": "number",
                          "minimum": 0,
                          "description": "Approximate USD cost of the model call, computed from token\nusage and published list prices. Used by the daily-budget\nguard at `LLM_VERIFY_DAILY_BUDGET_USD`.\n"
                        },
                        "reason": {
                          "type": "string",
                          "enum": [
                            "verdict_not_eligible",
                            "daily_budget_exceeded",
                            "no_gateway",
                            "upstream_error",
                            "malformed_response"
                          ],
                          "description": "Set when `applied: false`. `verdict_not_eligible` means the\npre-LLM verdict was not `mismatch / low` so no model call was\nattempted.\n"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "parseErrors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "index",
                "error",
                "message"
              ],
              "properties": {
                "index": {
                  "type": "integer"
                },
                "error": {
                  "type": "string",
                  "description": "e.g. \"missing_title\", \"invalid_syntax\", \"empty_entry\", \"unsupported_type\"."
                },
                "message": {
                  "type": "string"
                }
              }
            }
          },
          "truncated": {
            "type": "integer",
            "description": "Entries dropped beyond the 25-entry cap."
          },
          "summary": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "total",
              "matched",
              "mismatch",
              "ambiguous",
              "not_found",
              "errored",
              "retracted"
            ],
            "description": "Corpus roll-up (a pure function of `entries`).",
            "properties": {
              "total": {
                "type": "integer"
              },
              "matched": {
                "type": "integer"
              },
              "mismatch": {
                "type": "integer"
              },
              "ambiguous": {
                "type": "integer"
              },
              "not_found": {
                "type": "integer"
              },
              "errored": {
                "type": "integer"
              },
              "retracted": {
                "type": "integer"
              }
            }
          }
        }
      },
      "DetectSuccessBody": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "count",
          "identifiers"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Length of `identifiers`."
          },
          "identifiers": {
            "type": "array",
            "description": "De-duplicated by `(type, value)`, in detection order.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "type",
                "value"
              ],
              "description": "One detected identifier. `raw` and `source` are present only when the\ndetector kept the original token or recorded which pass matched — do\nnot depend on either being set.\n",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "doi",
                    "pmid",
                    "pmcid",
                    "isbn",
                    "arxiv",
                    "issn",
                    "eissn",
                    "ads",
                    "url"
                  ],
                  "description": "`url` is emitted for a recognized scholarly host that is not\nalready covered by a more specific identifier.\n"
                },
                "value": {
                  "type": "string",
                  "description": "Canonical form of the identifier."
                },
                "raw": {
                  "type": "string",
                  "description": "Original token, when it differs from `value`."
                },
                "source": {
                  "type": "string",
                  "description": "Detector pass that matched, e.g. `detect:url`."
                }
              }
            }
          }
        }
      },
      "SlimItem": {
        "type": "object",
        "additionalProperties": true,
        "description": "Compact, response-safe view of a resolved bibliographic record — the\nsame slim shape the format routes build their items from. Every field\nexcept `id` is optional, because a record carries only what its source\nsupplied.\n",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable item key derived from the identifiers."
          },
          "type": {
            "type": "string",
            "description": "CSL item type (e.g. `article-journal`, `book`, `chapter`, `dataset`)."
          },
          "title": {
            "type": "string"
          },
          "authors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "description": "A person. Structured records carry `family`/`given`; sources that\nsupply an unsplittable name use `literal` instead.\n",
              "properties": {
                "family": {
                  "type": "string"
                },
                "given": {
                  "type": "string"
                },
                "suffix": {
                  "type": "string"
                },
                "literal": {
                  "type": "string"
                }
              }
            }
          },
          "container": {
            "type": "object",
            "additionalProperties": true,
            "description": "Journal or book the work appears in.",
            "properties": {
              "title": {
                "type": "string"
              },
              "abbreviated": {
                "type": "string"
              },
              "volume": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "integer"
                  }
                ]
              },
              "issue": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "integer"
                  }
                ]
              },
              "issn": {
                "type": "string",
                "description": "Print ISSN of the serial."
              },
              "eissn": {
                "type": "string",
                "description": "Electronic ISSN of the serial."
              }
            }
          },
          "identifiers": {
            "type": "array",
            "description": "Present only when the record carries at least one identifier.",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "required": [
                "type",
                "value"
              ],
              "properties": {
                "type": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            }
          },
          "issued": {
            "type": "object",
            "additionalProperties": true,
            "description": "Present only when the record carries a publication year.",
            "properties": {
              "year": {
                "type": "integer"
              }
            }
          },
          "pages": {
            "type": "object",
            "additionalProperties": true,
            "description": "Present only when the record carries a first or last page.",
            "properties": {
              "first": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "integer"
                  }
                ]
              },
              "last": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "integer"
                  }
                ]
              }
            }
          },
          "number": {
            "allOf": [
              {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "integer"
                  }
                ]
              }
            ],
            "description": "Report or thesis number, where the record carries one."
          },
          "url": {
            "type": "string"
          },
          "_source": {
            "description": "Which upstream service supplied the record.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object",
                "additionalProperties": true,
                "properties": {
                  "service": {
                    "type": "string"
                  },
                  "requestUrl": {
                    "type": "string"
                  }
                }
              }
            ]
          },
          "_checks": {
            "type": "object",
            "description": "Sibling field on resolved items; populated only when ?checks= is set.",
            "additionalProperties": false,
            "properties": {
              "retraction": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "ok",
                      "retracted",
                      "concern",
                      "correction",
                      "unknown"
                    ]
                  },
                  "notices": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "type": {
                          "type": "string",
                          "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                        },
                        "label": {
                          "type": "string"
                        },
                        "doi": {
                          "type": "string",
                          "nullable": true
                        },
                        "date": {
                          "type": "string",
                          "nullable": true
                        },
                        "source": {
                          "type": "string",
                          "nullable": true
                        }
                      }
                    }
                  },
                  "error": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "code": {
                        "type": "string"
                      },
                      "message": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "open_access": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "open",
                      "closed",
                      "unknown"
                    ]
                  },
                  "oa_status": {
                    "type": "string",
                    "enum": [
                      "gold",
                      "green",
                      "hybrid",
                      "bronze",
                      "closed"
                    ]
                  },
                  "best_url": {
                    "type": "string"
                  },
                  "pdf_url": {
                    "type": "string",
                    "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                    "nullable": true
                  },
                  "license": {
                    "type": "string",
                    "nullable": true
                  },
                  "version": {
                    "type": "string",
                    "nullable": true
                  },
                  "error": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "code": {
                        "type": "string"
                      },
                      "message": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "doaj": {
                "type": "object",
                "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
                "additionalProperties": false,
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "indexed",
                      "not_indexed",
                      "unknown"
                    ]
                  },
                  "in_doaj": {
                    "type": "boolean"
                  },
                  "title": {
                    "type": "string",
                    "description": "DOAJ's journal title (match confirmation)."
                  },
                  "license": {
                    "type": "string",
                    "description": "Primary licence type, e.g. \"CC BY\"."
                  },
                  "issn": {
                    "type": "string",
                    "description": "ISSN matched on (normalised NNNN-NNNX)."
                  },
                  "url": {
                    "type": "string",
                    "description": "Canonical DOAJ table-of-contents URL for the journal."
                  },
                  "error": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "code": {
                        "type": "string"
                      },
                      "message": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "_provenance": {
            "type": "object",
            "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
            "additionalProperties": false,
            "required": [
              "transform_version",
              "sources",
              "resolved_at"
            ],
            "properties": {
              "transform_version": {
                "type": "string",
                "description": "Pinned dep digest mirroring x-scholar-transform-version."
              },
              "resolved_at": {
                "type": "string",
                "format": "date-time"
              },
              "request_id": {
                "type": "string",
                "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
              },
              "sources": {
                "type": "array",
                "description": "Sources that contributed the winning record (V2 emits the single winner).",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name"
                  ],
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Source service name (e.g., \"crossref\")"
                    },
                    "url": {
                      "type": "string"
                    },
                    "fetched_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When this process fetched the record."
                    },
                    "upstream_fetched_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                    },
                    "cache": {
                      "type": "string",
                      "enum": [
                        "hit",
                        "miss",
                        "bypass"
                      ]
                    },
                    "role": {
                      "type": "string",
                      "enum": [
                        "primary",
                        "fallback"
                      ],
                      "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                    },
                    "ttl_band": {
                      "type": "string",
                      "enum": [
                        "recent",
                        "mid",
                        "frozen"
                      ],
                      "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                    }
                  }
                }
              },
              "fallbacks_tried": {
                "type": "array",
                "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "outcome"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "won",
                        "not_found",
                        "error",
                        "empty",
                        "skipped"
                      ]
                    },
                    "reason": {
                      "type": "string"
                    }
                  }
                }
              },
              "fields_from_source": {
                "type": "array",
                "description": "CSL-relevant fields the upstream record populated.",
                "items": {
                  "type": "string"
                }
              },
              "fields_absent": {
                "type": "array",
                "description": "CSL-relevant fields the schema permits but upstream did not supply.",
                "items": {
                  "type": "string"
                }
              },
              "normalization": {
                "type": "array",
                "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "rule",
                    "from",
                    "to"
                  ],
                  "properties": {
                    "rule": {
                      "type": "string",
                      "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                    },
                    "from": {
                      "type": "string"
                    },
                    "to": {
                      "type": "string"
                    }
                  }
                }
              },
              "field_provenance": {
                "type": "object",
                "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
                "additionalProperties": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "source"
                  ],
                  "properties": {
                    "source": {
                      "type": "string"
                    },
                    "upstream_fetched_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              },
              "full_metadata": {
                "type": "object",
                "description": "Rich linked-data graph; present only under ?provenance=full.",
                "additionalProperties": false,
                "properties": {
                  "funders": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "doi": {
                          "type": "string"
                        },
                        "award": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "orcids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "ror_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "license": {
                    "type": "string",
                    "nullable": true
                  },
                  "clinical_trial_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "trust_signals": {
                "type": "object",
                "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
                "additionalProperties": false,
                "properties": {
                  "retraction": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "requested",
                      "evaluated"
                    ],
                    "properties": {
                      "requested": {
                        "type": "boolean"
                      },
                      "evaluated": {
                        "type": "boolean"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "ok",
                          "retracted",
                          "concern",
                          "correction",
                          "unknown"
                        ]
                      },
                      "skipped_reason": {
                        "type": "string",
                        "enum": [
                          "no_doi"
                        ]
                      }
                    }
                  },
                  "open_access": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "requested",
                      "evaluated"
                    ],
                    "properties": {
                      "requested": {
                        "type": "boolean"
                      },
                      "evaluated": {
                        "type": "boolean"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "open",
                          "closed",
                          "unknown"
                        ]
                      },
                      "oa_status": {
                        "type": "string",
                        "enum": [
                          "gold",
                          "green",
                          "hybrid",
                          "bronze",
                          "closed"
                        ]
                      },
                      "pdf_url": {
                        "type": "string",
                        "nullable": true
                      },
                      "skipped_reason": {
                        "type": "string",
                        "enum": [
                          "no_doi"
                        ]
                      }
                    }
                  }
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "strict",
                  "best-effort"
                ],
                "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
              },
              "selection_reason": {
                "type": "string",
                "enum": [
                  "static_chain_position"
                ],
                "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
              },
              "container_only": {
                "type": "boolean",
                "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
              },
              "conflicts": {
                "type": "object",
                "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
                "additionalProperties": false,
                "required": [
                  "status"
                ],
                "properties": {
                  "checked_against": {
                    "type": "string",
                    "description": "The independent source cross-checked against (omitted when none available)."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "agreed",
                      "conflict",
                      "unavailable"
                    ]
                  },
                  "skipped_reason": {
                    "type": "string",
                    "enum": [
                      "no_secondary_source",
                      "upstream_error",
                      "not_found"
                    ]
                  },
                  "fields": {
                    "type": "array",
                    "description": "Field-level disagreements; present only when status is `conflict`.",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "field",
                        "primary",
                        "secondary"
                      ],
                      "properties": {
                        "field": {
                          "type": "string",
                          "enum": [
                            "title",
                            "first_author",
                            "year",
                            "container"
                          ]
                        },
                        "primary": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "source",
                            "value"
                          ],
                          "properties": {
                            "source": {
                              "type": "string"
                            },
                            "value": {
                              "oneOf": [
                                {
                                  "type": "string"
                                },
                                {
                                  "type": "number"
                                }
                              ]
                            }
                          }
                        },
                        "secondary": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "source",
                            "value"
                          ],
                          "properties": {
                            "source": {
                              "type": "string"
                            },
                            "value": {
                              "oneOf": [
                                {
                                  "type": "string"
                                },
                                {
                                  "type": "number"
                                }
                              ]
                            }
                          }
                        },
                        "similarity": {
                          "type": "number",
                          "description": "Similarity score (0–1) for fuzzy fields."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "LookupSuccessBody": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "input",
          "result"
        ],
        "description": "`result` is `null` with `reason: \"not_found\"` when the identifier was\nrecognized but resolved to no record. That is a 200, not an error.\n",
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "input": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "type",
              "value"
            ],
            "description": "The first identifier detected in the request, canonicalized.",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "doi",
                  "pmid",
                  "pmcid",
                  "isbn",
                  "arxiv",
                  "issn",
                  "eissn",
                  "ads",
                  "url"
                ]
              },
              "value": {
                "type": "string"
              }
            }
          },
          "result": {
            "description": "The resolved record, or `null` when nothing resolved.",
            "type": "object",
            "allOf": [
              {
                "type": "object",
                "additionalProperties": true,
                "description": "Compact, response-safe view of a resolved bibliographic record — the\nsame slim shape the format routes build their items from. Every field\nexcept `id` is optional, because a record carries only what its source\nsupplied.\n",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable item key derived from the identifiers."
                  },
                  "type": {
                    "type": "string",
                    "description": "CSL item type (e.g. `article-journal`, `book`, `chapter`, `dataset`)."
                  },
                  "title": {
                    "type": "string"
                  },
                  "authors": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "A person. Structured records carry `family`/`given`; sources that\nsupply an unsplittable name use `literal` instead.\n",
                      "properties": {
                        "family": {
                          "type": "string"
                        },
                        "given": {
                          "type": "string"
                        },
                        "suffix": {
                          "type": "string"
                        },
                        "literal": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "container": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Journal or book the work appears in.",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "abbreviated": {
                        "type": "string"
                      },
                      "volume": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "integer"
                          }
                        ]
                      },
                      "issue": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "integer"
                          }
                        ]
                      },
                      "issn": {
                        "type": "string",
                        "description": "Print ISSN of the serial."
                      },
                      "eissn": {
                        "type": "string",
                        "description": "Electronic ISSN of the serial."
                      }
                    }
                  },
                  "identifiers": {
                    "type": "array",
                    "description": "Present only when the record carries at least one identifier.",
                    "items": {
                      "type": "object",
                      "additionalProperties": true,
                      "required": [
                        "type",
                        "value"
                      ],
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "value": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "issued": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Present only when the record carries a publication year.",
                    "properties": {
                      "year": {
                        "type": "integer"
                      }
                    }
                  },
                  "pages": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Present only when the record carries a first or last page.",
                    "properties": {
                      "first": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "integer"
                          }
                        ]
                      },
                      "last": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "integer"
                          }
                        ]
                      }
                    }
                  },
                  "number": {
                    "allOf": [
                      {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "integer"
                          }
                        ]
                      }
                    ],
                    "description": "Report or thesis number, where the record carries one."
                  },
                  "url": {
                    "type": "string"
                  },
                  "_source": {
                    "description": "Which upstream service supplied the record.",
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "service": {
                            "type": "string"
                          },
                          "requestUrl": {
                            "type": "string"
                          }
                        }
                      }
                    ]
                  },
                  "_checks": {
                    "type": "object",
                    "description": "Sibling field on resolved items; populated only when ?checks= is set.",
                    "additionalProperties": false,
                    "properties": {
                      "retraction": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "ok",
                              "retracted",
                              "concern",
                              "correction",
                              "unknown"
                            ]
                          },
                          "notices": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "properties": {
                                "type": {
                                  "type": "string",
                                  "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                                },
                                "label": {
                                  "type": "string"
                                },
                                "doi": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "date": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "source": {
                                  "type": "string",
                                  "nullable": true
                                }
                              }
                            }
                          },
                          "error": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      },
                      "open_access": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "open",
                              "closed",
                              "unknown"
                            ]
                          },
                          "oa_status": {
                            "type": "string",
                            "enum": [
                              "gold",
                              "green",
                              "hybrid",
                              "bronze",
                              "closed"
                            ]
                          },
                          "best_url": {
                            "type": "string"
                          },
                          "pdf_url": {
                            "type": "string",
                            "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                            "nullable": true
                          },
                          "license": {
                            "type": "string",
                            "nullable": true
                          },
                          "version": {
                            "type": "string",
                            "nullable": true
                          },
                          "error": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      },
                      "doaj": {
                        "type": "object",
                        "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
                        "additionalProperties": false,
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "indexed",
                              "not_indexed",
                              "unknown"
                            ]
                          },
                          "in_doaj": {
                            "type": "boolean"
                          },
                          "title": {
                            "type": "string",
                            "description": "DOAJ's journal title (match confirmation)."
                          },
                          "license": {
                            "type": "string",
                            "description": "Primary licence type, e.g. \"CC BY\"."
                          },
                          "issn": {
                            "type": "string",
                            "description": "ISSN matched on (normalised NNNN-NNNX)."
                          },
                          "url": {
                            "type": "string",
                            "description": "Canonical DOAJ table-of-contents URL for the journal."
                          },
                          "error": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "_provenance": {
                    "type": "object",
                    "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
                    "additionalProperties": false,
                    "required": [
                      "transform_version",
                      "sources",
                      "resolved_at"
                    ],
                    "properties": {
                      "transform_version": {
                        "type": "string",
                        "description": "Pinned dep digest mirroring x-scholar-transform-version."
                      },
                      "resolved_at": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "request_id": {
                        "type": "string",
                        "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
                      },
                      "sources": {
                        "type": "array",
                        "description": "Sources that contributed the winning record (V2 emits the single winner).",
                        "items": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "name"
                          ],
                          "properties": {
                            "name": {
                              "type": "string",
                              "description": "Source service name (e.g., \"crossref\")"
                            },
                            "url": {
                              "type": "string"
                            },
                            "fetched_at": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When this process fetched the record."
                            },
                            "upstream_fetched_at": {
                              "type": "string",
                              "format": "date-time",
                              "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                            },
                            "cache": {
                              "type": "string",
                              "enum": [
                                "hit",
                                "miss",
                                "bypass"
                              ]
                            },
                            "role": {
                              "type": "string",
                              "enum": [
                                "primary",
                                "fallback"
                              ],
                              "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                            },
                            "ttl_band": {
                              "type": "string",
                              "enum": [
                                "recent",
                                "mid",
                                "frozen"
                              ],
                              "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                            }
                          }
                        }
                      },
                      "fallbacks_tried": {
                        "type": "array",
                        "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
                        "items": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "name",
                            "outcome"
                          ],
                          "properties": {
                            "name": {
                              "type": "string"
                            },
                            "outcome": {
                              "type": "string",
                              "enum": [
                                "won",
                                "not_found",
                                "error",
                                "empty",
                                "skipped"
                              ]
                            },
                            "reason": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "fields_from_source": {
                        "type": "array",
                        "description": "CSL-relevant fields the upstream record populated.",
                        "items": {
                          "type": "string"
                        }
                      },
                      "fields_absent": {
                        "type": "array",
                        "description": "CSL-relevant fields the schema permits but upstream did not supply.",
                        "items": {
                          "type": "string"
                        }
                      },
                      "normalization": {
                        "type": "array",
                        "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
                        "items": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "rule",
                            "from",
                            "to"
                          ],
                          "properties": {
                            "rule": {
                              "type": "string",
                              "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                            },
                            "from": {
                              "type": "string"
                            },
                            "to": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "field_provenance": {
                        "type": "object",
                        "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
                        "additionalProperties": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "source"
                          ],
                          "properties": {
                            "source": {
                              "type": "string"
                            },
                            "upstream_fetched_at": {
                              "type": "string",
                              "format": "date-time"
                            }
                          }
                        }
                      },
                      "full_metadata": {
                        "type": "object",
                        "description": "Rich linked-data graph; present only under ?provenance=full.",
                        "additionalProperties": false,
                        "properties": {
                          "funders": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "properties": {
                                "name": {
                                  "type": "string"
                                },
                                "doi": {
                                  "type": "string"
                                },
                                "award": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          },
                          "orcids": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "ror_ids": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "license": {
                            "type": "string",
                            "nullable": true
                          },
                          "clinical_trial_ids": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "trust_signals": {
                        "type": "object",
                        "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
                        "additionalProperties": false,
                        "properties": {
                          "retraction": {
                            "type": "object",
                            "additionalProperties": false,
                            "required": [
                              "requested",
                              "evaluated"
                            ],
                            "properties": {
                              "requested": {
                                "type": "boolean"
                              },
                              "evaluated": {
                                "type": "boolean"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "ok",
                                  "retracted",
                                  "concern",
                                  "correction",
                                  "unknown"
                                ]
                              },
                              "skipped_reason": {
                                "type": "string",
                                "enum": [
                                  "no_doi"
                                ]
                              }
                            }
                          },
                          "open_access": {
                            "type": "object",
                            "additionalProperties": false,
                            "required": [
                              "requested",
                              "evaluated"
                            ],
                            "properties": {
                              "requested": {
                                "type": "boolean"
                              },
                              "evaluated": {
                                "type": "boolean"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "open",
                                  "closed",
                                  "unknown"
                                ]
                              },
                              "oa_status": {
                                "type": "string",
                                "enum": [
                                  "gold",
                                  "green",
                                  "hybrid",
                                  "bronze",
                                  "closed"
                                ]
                              },
                              "pdf_url": {
                                "type": "string",
                                "nullable": true
                              },
                              "skipped_reason": {
                                "type": "string",
                                "enum": [
                                  "no_doi"
                                ]
                              }
                            }
                          }
                        }
                      },
                      "mode": {
                        "type": "string",
                        "enum": [
                          "strict",
                          "best-effort"
                        ],
                        "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
                      },
                      "selection_reason": {
                        "type": "string",
                        "enum": [
                          "static_chain_position"
                        ],
                        "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
                      },
                      "container_only": {
                        "type": "boolean",
                        "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
                      },
                      "conflicts": {
                        "type": "object",
                        "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
                        "additionalProperties": false,
                        "required": [
                          "status"
                        ],
                        "properties": {
                          "checked_against": {
                            "type": "string",
                            "description": "The independent source cross-checked against (omitted when none available)."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "agreed",
                              "conflict",
                              "unavailable"
                            ]
                          },
                          "skipped_reason": {
                            "type": "string",
                            "enum": [
                              "no_secondary_source",
                              "upstream_error",
                              "not_found"
                            ]
                          },
                          "fields": {
                            "type": "array",
                            "description": "Field-level disagreements; present only when status is `conflict`.",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "field",
                                "primary",
                                "secondary"
                              ],
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "enum": [
                                    "title",
                                    "first_author",
                                    "year",
                                    "container"
                                  ]
                                },
                                "primary": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "source",
                                    "value"
                                  ],
                                  "properties": {
                                    "source": {
                                      "type": "string"
                                    },
                                    "value": {
                                      "oneOf": [
                                        {
                                          "type": "string"
                                        },
                                        {
                                          "type": "number"
                                        }
                                      ]
                                    }
                                  }
                                },
                                "secondary": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "source",
                                    "value"
                                  ],
                                  "properties": {
                                    "source": {
                                      "type": "string"
                                    },
                                    "value": {
                                      "oneOf": [
                                        {
                                          "type": "string"
                                        },
                                        {
                                          "type": "number"
                                        }
                                      ]
                                    }
                                  }
                                },
                                "similarity": {
                                  "type": "number",
                                  "description": "Similarity score (0–1) for fuzzy fields."
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            ],
            "nullable": true
          },
          "reason": {
            "type": "string",
            "enum": [
              "not_found"
            ],
            "description": "Present only when `result` is `null`."
          }
        }
      },
      "RetractionResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "isRetracted": {
            "type": "boolean"
          },
          "hasCorrections": {
            "type": "boolean"
          },
          "hasConcern": {
            "type": "boolean"
          },
          "notices": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "type": "string",
                  "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                },
                "label": {
                  "type": "string"
                },
                "doi": {
                  "type": "string",
                  "nullable": true
                },
                "date": {
                  "type": "string",
                  "nullable": true
                },
                "source": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          },
          "title": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RetractionCheckResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "doi",
          "result"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "doi": {
            "type": "string",
            "description": "Resolved DOI, or null when no DOI was found",
            "nullable": true
          },
          "resolvedFrom": {
            "type": "object",
            "description": "Original identifier when different from the resolved DOI",
            "properties": {
              "type": {
                "type": "string"
              },
              "value": {
                "type": "string"
              }
            }
          },
          "reason": {
            "type": "string",
            "description": "Optional reason code (e.g., \"no_doi\")"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "isRetracted": {
                "type": "boolean"
              },
              "hasCorrections": {
                "type": "boolean"
              },
              "hasConcern": {
                "type": "boolean"
              },
              "notices": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                    },
                    "label": {
                      "type": "string"
                    },
                    "doi": {
                      "type": "string",
                      "nullable": true
                    },
                    "date": {
                      "type": "string",
                      "nullable": true
                    },
                    "source": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              },
              "title": {
                "type": "string",
                "nullable": true
              }
            },
            "nullable": true
          }
        }
      },
      "OaResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "isOa": {
            "type": "boolean"
          },
          "oaStatus": {
            "type": "string",
            "enum": [
              "gold",
              "green",
              "hybrid",
              "bronze",
              "closed"
            ]
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "bestLocation": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "url": {
                "type": "string"
              },
              "hostType": {
                "type": "string"
              },
              "license": {
                "type": "string",
                "nullable": true
              },
              "version": {
                "type": "string",
                "nullable": true
              }
            },
            "nullable": true
          },
          "locations": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "url": {
                  "type": "string"
                },
                "hostType": {
                  "type": "string"
                },
                "license": {
                  "type": "string",
                  "nullable": true
                },
                "version": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "OaCheckResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "doi",
          "result"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "doi": {
            "type": "string",
            "nullable": true
          },
          "resolvedFrom": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string"
              },
              "value": {
                "type": "string"
              }
            }
          },
          "reason": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "isOa": {
                "type": "boolean"
              },
              "oaStatus": {
                "type": "string",
                "enum": [
                  "gold",
                  "green",
                  "hybrid",
                  "bronze",
                  "closed"
                ]
              },
              "title": {
                "type": "string",
                "nullable": true
              },
              "bestLocation": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "url": {
                    "type": "string"
                  },
                  "hostType": {
                    "type": "string"
                  },
                  "license": {
                    "type": "string",
                    "nullable": true
                  },
                  "version": {
                    "type": "string",
                    "nullable": true
                  }
                },
                "nullable": true
              },
              "locations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "url": {
                      "type": "string"
                    },
                    "hostType": {
                      "type": "string"
                    },
                    "license": {
                      "type": "string",
                      "nullable": true
                    },
                    "version": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            },
            "nullable": true
          }
        }
      },
      "ChecksMeta": {
        "type": "object",
        "description": "Sibling field on resolved items; populated only when ?checks= is set.",
        "additionalProperties": false,
        "properties": {
          "retraction": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "ok",
                  "retracted",
                  "concern",
                  "correction",
                  "unknown"
                ]
              },
              "notices": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                    },
                    "label": {
                      "type": "string"
                    },
                    "doi": {
                      "type": "string",
                      "nullable": true
                    },
                    "date": {
                      "type": "string",
                      "nullable": true
                    },
                    "source": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              },
              "error": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "open_access": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "open",
                  "closed",
                  "unknown"
                ]
              },
              "oa_status": {
                "type": "string",
                "enum": [
                  "gold",
                  "green",
                  "hybrid",
                  "bronze",
                  "closed"
                ]
              },
              "best_url": {
                "type": "string"
              },
              "pdf_url": {
                "type": "string",
                "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                "nullable": true
              },
              "license": {
                "type": "string",
                "nullable": true
              },
              "version": {
                "type": "string",
                "nullable": true
              },
              "error": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "doaj": {
            "type": "object",
            "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
            "additionalProperties": false,
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "indexed",
                  "not_indexed",
                  "unknown"
                ]
              },
              "in_doaj": {
                "type": "boolean"
              },
              "title": {
                "type": "string",
                "description": "DOAJ's journal title (match confirmation)."
              },
              "license": {
                "type": "string",
                "description": "Primary licence type, e.g. \"CC BY\"."
              },
              "issn": {
                "type": "string",
                "description": "ISSN matched on (normalised NNNN-NNNX)."
              },
              "url": {
                "type": "string",
                "description": "Canonical DOAJ table-of-contents URL for the journal."
              },
              "error": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "ProvenanceMeta": {
        "type": "object",
        "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
        "additionalProperties": false,
        "required": [
          "transform_version",
          "sources",
          "resolved_at"
        ],
        "properties": {
          "transform_version": {
            "type": "string",
            "description": "Pinned dep digest mirroring x-scholar-transform-version."
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time"
          },
          "request_id": {
            "type": "string",
            "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
          },
          "sources": {
            "type": "array",
            "description": "Sources that contributed the winning record (V2 emits the single winner).",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "name"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Source service name (e.g., \"crossref\")"
                },
                "url": {
                  "type": "string"
                },
                "fetched_at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "When this process fetched the record."
                },
                "upstream_fetched_at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                },
                "cache": {
                  "type": "string",
                  "enum": [
                    "hit",
                    "miss",
                    "bypass"
                  ]
                },
                "role": {
                  "type": "string",
                  "enum": [
                    "primary",
                    "fallback"
                  ],
                  "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                },
                "ttl_band": {
                  "type": "string",
                  "enum": [
                    "recent",
                    "mid",
                    "frozen"
                  ],
                  "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                }
              }
            }
          },
          "fallbacks_tried": {
            "type": "array",
            "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "name",
                "outcome"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "outcome": {
                  "type": "string",
                  "enum": [
                    "won",
                    "not_found",
                    "error",
                    "empty",
                    "skipped"
                  ]
                },
                "reason": {
                  "type": "string"
                }
              }
            }
          },
          "fields_from_source": {
            "type": "array",
            "description": "CSL-relevant fields the upstream record populated.",
            "items": {
              "type": "string"
            }
          },
          "fields_absent": {
            "type": "array",
            "description": "CSL-relevant fields the schema permits but upstream did not supply.",
            "items": {
              "type": "string"
            }
          },
          "normalization": {
            "type": "array",
            "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "rule",
                "from",
                "to"
              ],
              "properties": {
                "rule": {
                  "type": "string",
                  "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                },
                "from": {
                  "type": "string"
                },
                "to": {
                  "type": "string"
                }
              }
            }
          },
          "field_provenance": {
            "type": "object",
            "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
            "additionalProperties": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "source"
              ],
              "properties": {
                "source": {
                  "type": "string"
                },
                "upstream_fetched_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "full_metadata": {
            "type": "object",
            "description": "Rich linked-data graph; present only under ?provenance=full.",
            "additionalProperties": false,
            "properties": {
              "funders": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "doi": {
                      "type": "string"
                    },
                    "award": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "orcids": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "ror_ids": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "license": {
                "type": "string",
                "nullable": true
              },
              "clinical_trial_ids": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "trust_signals": {
            "type": "object",
            "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
            "additionalProperties": false,
            "properties": {
              "retraction": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "requested",
                  "evaluated"
                ],
                "properties": {
                  "requested": {
                    "type": "boolean"
                  },
                  "evaluated": {
                    "type": "boolean"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "ok",
                      "retracted",
                      "concern",
                      "correction",
                      "unknown"
                    ]
                  },
                  "skipped_reason": {
                    "type": "string",
                    "enum": [
                      "no_doi"
                    ]
                  }
                }
              },
              "open_access": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "requested",
                  "evaluated"
                ],
                "properties": {
                  "requested": {
                    "type": "boolean"
                  },
                  "evaluated": {
                    "type": "boolean"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "open",
                      "closed",
                      "unknown"
                    ]
                  },
                  "oa_status": {
                    "type": "string",
                    "enum": [
                      "gold",
                      "green",
                      "hybrid",
                      "bronze",
                      "closed"
                    ]
                  },
                  "pdf_url": {
                    "type": "string",
                    "nullable": true
                  },
                  "skipped_reason": {
                    "type": "string",
                    "enum": [
                      "no_doi"
                    ]
                  }
                }
              }
            }
          },
          "mode": {
            "type": "string",
            "enum": [
              "strict",
              "best-effort"
            ],
            "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
          },
          "selection_reason": {
            "type": "string",
            "enum": [
              "static_chain_position"
            ],
            "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
          },
          "container_only": {
            "type": "boolean",
            "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
          },
          "conflicts": {
            "type": "object",
            "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
            "additionalProperties": false,
            "required": [
              "status"
            ],
            "properties": {
              "checked_against": {
                "type": "string",
                "description": "The independent source cross-checked against (omitted when none available)."
              },
              "status": {
                "type": "string",
                "enum": [
                  "agreed",
                  "conflict",
                  "unavailable"
                ]
              },
              "skipped_reason": {
                "type": "string",
                "enum": [
                  "no_secondary_source",
                  "upstream_error",
                  "not_found"
                ]
              },
              "fields": {
                "type": "array",
                "description": "Field-level disagreements; present only when status is `conflict`.",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "field",
                    "primary",
                    "secondary"
                  ],
                  "properties": {
                    "field": {
                      "type": "string",
                      "enum": [
                        "title",
                        "first_author",
                        "year",
                        "container"
                      ]
                    },
                    "primary": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "source",
                        "value"
                      ],
                      "properties": {
                        "source": {
                          "type": "string"
                        },
                        "value": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            }
                          ]
                        }
                      }
                    },
                    "secondary": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "source",
                        "value"
                      ],
                      "properties": {
                        "source": {
                          "type": "string"
                        },
                        "value": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            }
                          ]
                        }
                      }
                    },
                    "similarity": {
                      "type": "number",
                      "description": "Similarity score (0–1) for fuzzy fields."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "EnrichedItem": {
        "type": "object",
        "additionalProperties": true,
        "description": "Slim bibliographic item view. Carries optional `_checks` and `_provenance`\nsibling fragments when the corresponding query flags are set on the request.\n",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "idx": {
            "type": "integer",
            "description": "First contributing input index."
          },
          "sourceIdxs": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "_checks": {
            "type": "object",
            "description": "Sibling field on resolved items; populated only when ?checks= is set.",
            "additionalProperties": false,
            "properties": {
              "retraction": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "ok",
                      "retracted",
                      "concern",
                      "correction",
                      "unknown"
                    ]
                  },
                  "notices": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "type": {
                          "type": "string",
                          "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                        },
                        "label": {
                          "type": "string"
                        },
                        "doi": {
                          "type": "string",
                          "nullable": true
                        },
                        "date": {
                          "type": "string",
                          "nullable": true
                        },
                        "source": {
                          "type": "string",
                          "nullable": true
                        }
                      }
                    }
                  },
                  "error": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "code": {
                        "type": "string"
                      },
                      "message": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "open_access": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "open",
                      "closed",
                      "unknown"
                    ]
                  },
                  "oa_status": {
                    "type": "string",
                    "enum": [
                      "gold",
                      "green",
                      "hybrid",
                      "bronze",
                      "closed"
                    ]
                  },
                  "best_url": {
                    "type": "string"
                  },
                  "pdf_url": {
                    "type": "string",
                    "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                    "nullable": true
                  },
                  "license": {
                    "type": "string",
                    "nullable": true
                  },
                  "version": {
                    "type": "string",
                    "nullable": true
                  },
                  "error": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "code": {
                        "type": "string"
                      },
                      "message": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "doaj": {
                "type": "object",
                "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
                "additionalProperties": false,
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "indexed",
                      "not_indexed",
                      "unknown"
                    ]
                  },
                  "in_doaj": {
                    "type": "boolean"
                  },
                  "title": {
                    "type": "string",
                    "description": "DOAJ's journal title (match confirmation)."
                  },
                  "license": {
                    "type": "string",
                    "description": "Primary licence type, e.g. \"CC BY\"."
                  },
                  "issn": {
                    "type": "string",
                    "description": "ISSN matched on (normalised NNNN-NNNX)."
                  },
                  "url": {
                    "type": "string",
                    "description": "Canonical DOAJ table-of-contents URL for the journal."
                  },
                  "error": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "code": {
                        "type": "string"
                      },
                      "message": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "_provenance": {
            "type": "object",
            "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
            "additionalProperties": false,
            "required": [
              "transform_version",
              "sources",
              "resolved_at"
            ],
            "properties": {
              "transform_version": {
                "type": "string",
                "description": "Pinned dep digest mirroring x-scholar-transform-version."
              },
              "resolved_at": {
                "type": "string",
                "format": "date-time"
              },
              "request_id": {
                "type": "string",
                "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
              },
              "sources": {
                "type": "array",
                "description": "Sources that contributed the winning record (V2 emits the single winner).",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name"
                  ],
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Source service name (e.g., \"crossref\")"
                    },
                    "url": {
                      "type": "string"
                    },
                    "fetched_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When this process fetched the record."
                    },
                    "upstream_fetched_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                    },
                    "cache": {
                      "type": "string",
                      "enum": [
                        "hit",
                        "miss",
                        "bypass"
                      ]
                    },
                    "role": {
                      "type": "string",
                      "enum": [
                        "primary",
                        "fallback"
                      ],
                      "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                    },
                    "ttl_band": {
                      "type": "string",
                      "enum": [
                        "recent",
                        "mid",
                        "frozen"
                      ],
                      "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                    }
                  }
                }
              },
              "fallbacks_tried": {
                "type": "array",
                "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "outcome"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "won",
                        "not_found",
                        "error",
                        "empty",
                        "skipped"
                      ]
                    },
                    "reason": {
                      "type": "string"
                    }
                  }
                }
              },
              "fields_from_source": {
                "type": "array",
                "description": "CSL-relevant fields the upstream record populated.",
                "items": {
                  "type": "string"
                }
              },
              "fields_absent": {
                "type": "array",
                "description": "CSL-relevant fields the schema permits but upstream did not supply.",
                "items": {
                  "type": "string"
                }
              },
              "normalization": {
                "type": "array",
                "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "rule",
                    "from",
                    "to"
                  ],
                  "properties": {
                    "rule": {
                      "type": "string",
                      "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                    },
                    "from": {
                      "type": "string"
                    },
                    "to": {
                      "type": "string"
                    }
                  }
                }
              },
              "field_provenance": {
                "type": "object",
                "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
                "additionalProperties": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "source"
                  ],
                  "properties": {
                    "source": {
                      "type": "string"
                    },
                    "upstream_fetched_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              },
              "full_metadata": {
                "type": "object",
                "description": "Rich linked-data graph; present only under ?provenance=full.",
                "additionalProperties": false,
                "properties": {
                  "funders": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "doi": {
                          "type": "string"
                        },
                        "award": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "orcids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "ror_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "license": {
                    "type": "string",
                    "nullable": true
                  },
                  "clinical_trial_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "trust_signals": {
                "type": "object",
                "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
                "additionalProperties": false,
                "properties": {
                  "retraction": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "requested",
                      "evaluated"
                    ],
                    "properties": {
                      "requested": {
                        "type": "boolean"
                      },
                      "evaluated": {
                        "type": "boolean"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "ok",
                          "retracted",
                          "concern",
                          "correction",
                          "unknown"
                        ]
                      },
                      "skipped_reason": {
                        "type": "string",
                        "enum": [
                          "no_doi"
                        ]
                      }
                    }
                  },
                  "open_access": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "requested",
                      "evaluated"
                    ],
                    "properties": {
                      "requested": {
                        "type": "boolean"
                      },
                      "evaluated": {
                        "type": "boolean"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "open",
                          "closed",
                          "unknown"
                        ]
                      },
                      "oa_status": {
                        "type": "string",
                        "enum": [
                          "gold",
                          "green",
                          "hybrid",
                          "bronze",
                          "closed"
                        ]
                      },
                      "pdf_url": {
                        "type": "string",
                        "nullable": true
                      },
                      "skipped_reason": {
                        "type": "string",
                        "enum": [
                          "no_doi"
                        ]
                      }
                    }
                  }
                }
              },
              "mode": {
                "type": "string",
                "enum": [
                  "strict",
                  "best-effort"
                ],
                "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
              },
              "selection_reason": {
                "type": "string",
                "enum": [
                  "static_chain_position"
                ],
                "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
              },
              "container_only": {
                "type": "boolean",
                "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
              },
              "conflicts": {
                "type": "object",
                "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
                "additionalProperties": false,
                "required": [
                  "status"
                ],
                "properties": {
                  "checked_against": {
                    "type": "string",
                    "description": "The independent source cross-checked against (omitted when none available)."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "agreed",
                      "conflict",
                      "unavailable"
                    ]
                  },
                  "skipped_reason": {
                    "type": "string",
                    "enum": [
                      "no_secondary_source",
                      "upstream_error",
                      "not_found"
                    ]
                  },
                  "fields": {
                    "type": "array",
                    "description": "Field-level disagreements; present only when status is `conflict`.",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "field",
                        "primary",
                        "secondary"
                      ],
                      "properties": {
                        "field": {
                          "type": "string",
                          "enum": [
                            "title",
                            "first_author",
                            "year",
                            "container"
                          ]
                        },
                        "primary": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "source",
                            "value"
                          ],
                          "properties": {
                            "source": {
                              "type": "string"
                            },
                            "value": {
                              "oneOf": [
                                {
                                  "type": "string"
                                },
                                {
                                  "type": "number"
                                }
                              ]
                            }
                          }
                        },
                        "secondary": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "source",
                            "value"
                          ],
                          "properties": {
                            "source": {
                              "type": "string"
                            },
                            "value": {
                              "oneOf": [
                                {
                                  "type": "string"
                                },
                                {
                                  "type": "number"
                                }
                              ]
                            }
                          }
                        },
                        "similarity": {
                          "type": "number",
                          "description": "Similarity score (0–1) for fuzzy fields."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "FormatSuccessBody": {
        "type": "object",
        "additionalProperties": true,
        "description": "Successful format response. `items[]` is always populated by /api/format and\nis populated by /api/format-items only when `?checks=` or `?provenance=1` is set.\n",
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "formatter": {
            "type": "string",
            "enum": [
              "builtin",
              "csl"
            ]
          },
          "styleRequested": {
            "type": "string",
            "nullable": true
          },
          "styleUsed": {
            "type": "string"
          },
          "lang": {
            "type": "string"
          },
          "footnote": {
            "type": "boolean"
          },
          "outputMode": {
            "type": "string",
            "enum": [
              "text",
              "html",
              "json"
            ]
          },
          "itemsIn": {
            "type": "integer"
          },
          "itemsOut": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "description": "Slim bibliographic item view. Carries optional `_checks` and `_provenance`\nsibling fragments when the corresponding query flags are set on the request.\n",
              "properties": {
                "id": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "idx": {
                  "type": "integer",
                  "description": "First contributing input index."
                },
                "sourceIdxs": {
                  "type": "array",
                  "items": {
                    "type": "integer"
                  }
                },
                "_checks": {
                  "type": "object",
                  "description": "Sibling field on resolved items; populated only when ?checks= is set.",
                  "additionalProperties": false,
                  "properties": {
                    "retraction": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "ok",
                            "retracted",
                            "concern",
                            "correction",
                            "unknown"
                          ]
                        },
                        "notices": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "type": {
                                "type": "string",
                                "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                              },
                              "label": {
                                "type": "string"
                              },
                              "doi": {
                                "type": "string",
                                "nullable": true
                              },
                              "date": {
                                "type": "string",
                                "nullable": true
                              },
                              "source": {
                                "type": "string",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "error": {
                          "type": "object",
                          "additionalProperties": false,
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "open_access": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "open",
                            "closed",
                            "unknown"
                          ]
                        },
                        "oa_status": {
                          "type": "string",
                          "enum": [
                            "gold",
                            "green",
                            "hybrid",
                            "bronze",
                            "closed"
                          ]
                        },
                        "best_url": {
                          "type": "string"
                        },
                        "pdf_url": {
                          "type": "string",
                          "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                          "nullable": true
                        },
                        "license": {
                          "type": "string",
                          "nullable": true
                        },
                        "version": {
                          "type": "string",
                          "nullable": true
                        },
                        "error": {
                          "type": "object",
                          "additionalProperties": false,
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "doaj": {
                      "type": "object",
                      "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
                      "additionalProperties": false,
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "indexed",
                            "not_indexed",
                            "unknown"
                          ]
                        },
                        "in_doaj": {
                          "type": "boolean"
                        },
                        "title": {
                          "type": "string",
                          "description": "DOAJ's journal title (match confirmation)."
                        },
                        "license": {
                          "type": "string",
                          "description": "Primary licence type, e.g. \"CC BY\"."
                        },
                        "issn": {
                          "type": "string",
                          "description": "ISSN matched on (normalised NNNN-NNNX)."
                        },
                        "url": {
                          "type": "string",
                          "description": "Canonical DOAJ table-of-contents URL for the journal."
                        },
                        "error": {
                          "type": "object",
                          "additionalProperties": false,
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "_provenance": {
                  "type": "object",
                  "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
                  "additionalProperties": false,
                  "required": [
                    "transform_version",
                    "sources",
                    "resolved_at"
                  ],
                  "properties": {
                    "transform_version": {
                      "type": "string",
                      "description": "Pinned dep digest mirroring x-scholar-transform-version."
                    },
                    "resolved_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "request_id": {
                      "type": "string",
                      "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
                    },
                    "sources": {
                      "type": "array",
                      "description": "Sources that contributed the winning record (V2 emits the single winner).",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "name"
                        ],
                        "properties": {
                          "name": {
                            "type": "string",
                            "description": "Source service name (e.g., \"crossref\")"
                          },
                          "url": {
                            "type": "string"
                          },
                          "fetched_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When this process fetched the record."
                          },
                          "upstream_fetched_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                          },
                          "cache": {
                            "type": "string",
                            "enum": [
                              "hit",
                              "miss",
                              "bypass"
                            ]
                          },
                          "role": {
                            "type": "string",
                            "enum": [
                              "primary",
                              "fallback"
                            ],
                            "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                          },
                          "ttl_band": {
                            "type": "string",
                            "enum": [
                              "recent",
                              "mid",
                              "frozen"
                            ],
                            "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                          }
                        }
                      }
                    },
                    "fallbacks_tried": {
                      "type": "array",
                      "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "name",
                          "outcome"
                        ],
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "outcome": {
                            "type": "string",
                            "enum": [
                              "won",
                              "not_found",
                              "error",
                              "empty",
                              "skipped"
                            ]
                          },
                          "reason": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "fields_from_source": {
                      "type": "array",
                      "description": "CSL-relevant fields the upstream record populated.",
                      "items": {
                        "type": "string"
                      }
                    },
                    "fields_absent": {
                      "type": "array",
                      "description": "CSL-relevant fields the schema permits but upstream did not supply.",
                      "items": {
                        "type": "string"
                      }
                    },
                    "normalization": {
                      "type": "array",
                      "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "rule",
                          "from",
                          "to"
                        ],
                        "properties": {
                          "rule": {
                            "type": "string",
                            "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                          },
                          "from": {
                            "type": "string"
                          },
                          "to": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "field_provenance": {
                      "type": "object",
                      "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
                      "additionalProperties": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "source"
                        ],
                        "properties": {
                          "source": {
                            "type": "string"
                          },
                          "upstream_fetched_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "full_metadata": {
                      "type": "object",
                      "description": "Rich linked-data graph; present only under ?provenance=full.",
                      "additionalProperties": false,
                      "properties": {
                        "funders": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "doi": {
                                "type": "string"
                              },
                              "award": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        },
                        "orcids": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "ror_ids": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "license": {
                          "type": "string",
                          "nullable": true
                        },
                        "clinical_trial_ids": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "trust_signals": {
                      "type": "object",
                      "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
                      "additionalProperties": false,
                      "properties": {
                        "retraction": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "requested",
                            "evaluated"
                          ],
                          "properties": {
                            "requested": {
                              "type": "boolean"
                            },
                            "evaluated": {
                              "type": "boolean"
                            },
                            "status": {
                              "type": "string",
                              "enum": [
                                "ok",
                                "retracted",
                                "concern",
                                "correction",
                                "unknown"
                              ]
                            },
                            "skipped_reason": {
                              "type": "string",
                              "enum": [
                                "no_doi"
                              ]
                            }
                          }
                        },
                        "open_access": {
                          "type": "object",
                          "additionalProperties": false,
                          "required": [
                            "requested",
                            "evaluated"
                          ],
                          "properties": {
                            "requested": {
                              "type": "boolean"
                            },
                            "evaluated": {
                              "type": "boolean"
                            },
                            "status": {
                              "type": "string",
                              "enum": [
                                "open",
                                "closed",
                                "unknown"
                              ]
                            },
                            "oa_status": {
                              "type": "string",
                              "enum": [
                                "gold",
                                "green",
                                "hybrid",
                                "bronze",
                                "closed"
                              ]
                            },
                            "pdf_url": {
                              "type": "string",
                              "nullable": true
                            },
                            "skipped_reason": {
                              "type": "string",
                              "enum": [
                                "no_doi"
                              ]
                            }
                          }
                        }
                      }
                    },
                    "mode": {
                      "type": "string",
                      "enum": [
                        "strict",
                        "best-effort"
                      ],
                      "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
                    },
                    "selection_reason": {
                      "type": "string",
                      "enum": [
                        "static_chain_position"
                      ],
                      "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
                    },
                    "container_only": {
                      "type": "boolean",
                      "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
                    },
                    "conflicts": {
                      "type": "object",
                      "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
                      "additionalProperties": false,
                      "required": [
                        "status"
                      ],
                      "properties": {
                        "checked_against": {
                          "type": "string",
                          "description": "The independent source cross-checked against (omitted when none available)."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "agreed",
                            "conflict",
                            "unavailable"
                          ]
                        },
                        "skipped_reason": {
                          "type": "string",
                          "enum": [
                            "no_secondary_source",
                            "upstream_error",
                            "not_found"
                          ]
                        },
                        "fields": {
                          "type": "array",
                          "description": "Field-level disagreements; present only when status is `conflict`.",
                          "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "required": [
                              "field",
                              "primary",
                              "secondary"
                            ],
                            "properties": {
                              "field": {
                                "type": "string",
                                "enum": [
                                  "title",
                                  "first_author",
                                  "year",
                                  "container"
                                ]
                              },
                              "primary": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                  "source",
                                  "value"
                                ],
                                "properties": {
                                  "source": {
                                    "type": "string"
                                  },
                                  "value": {
                                    "oneOf": [
                                      {
                                        "type": "string"
                                      },
                                      {
                                        "type": "number"
                                      }
                                    ]
                                  }
                                }
                              },
                              "secondary": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                  "source",
                                  "value"
                                ],
                                "properties": {
                                  "source": {
                                    "type": "string"
                                  },
                                  "value": {
                                    "oneOf": [
                                      {
                                        "type": "string"
                                      },
                                      {
                                        "type": "number"
                                      }
                                    ]
                                  }
                                }
                              },
                              "similarity": {
                                "type": "number",
                                "description": "Similarity score (0–1) for fuzzy fields."
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "text": {
            "type": "string",
            "description": "Plain-text rendered citation(s)."
          },
          "html": {
            "type": "string",
            "description": "HTML rendered citation(s)."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "meta": {
            "type": "object",
            "additionalProperties": true,
            "description": "Phase 12b batch summary. Aggregate counts + a duplicate-group list for a\nrequest. Additive metadata only — it never changes the formatted output.\n`resolved` counts input lines that mapped to a work, so the buckets are\nself-consistent: `linesIn === resolved + notFound + errored + skipped`,\nand `duplicates === resolved - afterDedupe`. The same shape appears on the\nstream `done` frame. Error/skip buckets are best-effort and may differ\nslightly between /api/format (dedups failing lines) and\n/api/format/stream (counts them per occurrence).\n",
            "properties": {
              "linesIn": {
                "type": "integer",
                "description": "Total input lines."
              },
              "resolved": {
                "type": "integer",
                "description": "Input lines that resolved to a work."
              },
              "afterDedupe": {
                "type": "integer",
                "description": "Distinct works after de-duplication."
              },
              "duplicates": {
                "type": "integer",
                "description": "Collapsed duplicate lines (resolved - afterDedupe)."
              },
              "notFound": {
                "type": "integer",
                "description": "Lines that resolved to no record."
              },
              "errored": {
                "type": "integer",
                "description": "Lines that failed on an upstream/other error."
              },
              "skipped": {
                "type": "integer",
                "description": "ISSN-container / ADS-without-token lines skipped."
              },
              "warned": {
                "type": "integer",
                "description": "Count of batch warning strings."
              },
              "duplicateGroups": {
                "type": "array",
                "description": "One entry per item whose input lines collapsed (>1 source line).",
                "items": {
                  "type": "object",
                  "properties": {
                    "idx": {
                      "type": "integer",
                      "description": "First contributing input-line index."
                    },
                    "sourceIdxs": {
                      "type": "array",
                      "items": {
                        "type": "integer"
                      },
                      "description": "All input-line indices that collapsed into this item."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "responses": {
      "OkJsonWithRL": {
        "description": "OK",
        "headers": {
          "X-Request-Id": {
            "description": "Unique request correlation ID.",
            "schema": {
              "type": "string"
            }
          },
          "X-Auth-Source": {
            "description": "Where the auth came from (first-party, rapidapi, anonymous).",
            "schema": {
              "type": "string",
              "enum": [
                "first-party",
                "rapidapi",
                "anonymous"
              ]
            }
          },
          "X-Auth-Plan": {
            "description": "Effective plan for this request (Free/Developer/Pro/Enterprise).",
            "schema": {
              "type": "string"
            }
          },
          "X-Scholar-Checks": {
            "description": "Echo of the resolved enrichment checks (e.g. \"retraction,oa\") when ?checks= is honored.",
            "schema": {
              "type": "string"
            }
          },
          "X-Scholar-Provenance": {
            "description": "Set to \"1\" when ?provenance=1 is honored; \"full\" when ?provenance=full is honored.",
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "full"
              ]
            }
          },
          "X-Scholar-Resolver-Mode": {
            "description": "Resolver mode applied (currently always \"strict\"); set only when ?mode= is supplied.",
            "schema": {
              "type": "string",
              "enum": [
                "strict"
              ]
            }
          },
          "X-Scholar-Transform-Version": {
            "description": "Public, monotonically-versioned tag for normalisation + formatting\nlogic — returned on every response. Serves as the active API version\nunder the header-based versioning scheme.\n",
            "schema": {
              "type": "string",
              "example": "2026-08-18"
            }
          },
          "Idempotent-Replayed": {
            "description": "Set to \"true\" when this response was replayed from a prior request with\nthe same `Idempotency-Key` (not freshly computed).\n",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          },
          "Deprecation": {
            "description": "Present only on responses from a deprecated API version. Signals that\nthe version is deprecated (per the deprecation policy in the API\noverview); pair with `Sunset` for the retirement date.\n",
            "schema": {
              "type": "string"
            }
          },
          "Sunset": {
            "description": "Present only on deprecated API versions. RFC 8594 HTTP-date after which\nthe version is retired (minimum 180 days after the `Deprecation` notice).\n",
            "schema": {
              "type": "string"
            }
          },
          "X-RateLimit-Limit": {
            "description": "Maximum requests allowed in the current window.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          "X-RateLimit-Remaining": {
            "description": "Requests remaining in the current window.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          "X-RateLimit-Reset": {
            "description": "UTC epoch seconds when the window resets.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          "X-RateLimit-Reset-After": {
            "description": "Seconds until reset.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          "X-RateLimit-Policy": {
            "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Instructs clients not to cache.",
            "schema": {
              "type": "string",
              "enum": [
                "no-store"
              ]
            }
          },
          "Content-Security-Policy": {
            "description": "CSP controlling resource loading.",
            "schema": {
              "type": "string"
            }
          },
          "X-Content-Type-Options": {
            "description": "MIME type sniffing prevention.",
            "schema": {
              "type": "string",
              "enum": [
                "nosniff"
              ]
            }
          },
          "X-Frame-Options": {
            "description": "Clickjacking protection.",
            "schema": {
              "type": "string",
              "enum": [
                "DENY",
                "SAMEORIGIN"
              ]
            }
          },
          "Referrer-Policy": {
            "description": "Referrer information policy.",
            "schema": {
              "type": "string",
              "enum": [
                "no-referrer",
                "no-referrer-when-downgrade",
                "origin",
                "origin-when-cross-origin",
                "same-origin",
                "strict-origin",
                "strict-origin-when-cross-origin",
                "unsafe-url"
              ]
            }
          },
          "Permissions-Policy": {
            "description": "Feature policy controls.",
            "schema": {
              "type": "string"
            }
          },
          "Cross-Origin-Opener-Policy": {
            "description": "Cross-origin opener policy.",
            "schema": {
              "type": "string",
              "enum": [
                "same-origin",
                "same-origin-allow-popups",
                "unsafe-none"
              ]
            }
          },
          "Cross-Origin-Resource-Policy": {
            "description": "Cross-origin resource policy.",
            "schema": {
              "type": "string",
              "enum": [
                "same-origin",
                "same-site",
                "cross-origin"
              ]
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "additionalProperties": true,
              "description": "Successful format response. `items[]` is always populated by /api/format and\nis populated by /api/format-items only when `?checks=` or `?provenance=1` is set.\n",
              "properties": {
                "ok": {
                  "type": "boolean",
                  "enum": [
                    true
                  ]
                },
                "formatter": {
                  "type": "string",
                  "enum": [
                    "builtin",
                    "csl"
                  ]
                },
                "styleRequested": {
                  "type": "string",
                  "nullable": true
                },
                "styleUsed": {
                  "type": "string"
                },
                "lang": {
                  "type": "string"
                },
                "footnote": {
                  "type": "boolean"
                },
                "outputMode": {
                  "type": "string",
                  "enum": [
                    "text",
                    "html",
                    "json"
                  ]
                },
                "itemsIn": {
                  "type": "integer"
                },
                "itemsOut": {
                  "type": "integer"
                },
                "items": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Slim bibliographic item view. Carries optional `_checks` and `_provenance`\nsibling fragments when the corresponding query flags are set on the request.\n",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string"
                      },
                      "idx": {
                        "type": "integer",
                        "description": "First contributing input index."
                      },
                      "sourceIdxs": {
                        "type": "array",
                        "items": {
                          "type": "integer"
                        }
                      },
                      "_checks": {
                        "type": "object",
                        "description": "Sibling field on resolved items; populated only when ?checks= is set.",
                        "additionalProperties": false,
                        "properties": {
                          "retraction": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "status": {
                                "type": "string",
                                "enum": [
                                  "ok",
                                  "retracted",
                                  "concern",
                                  "correction",
                                  "unknown"
                                ]
                              },
                              "notices": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "properties": {
                                    "type": {
                                      "type": "string",
                                      "description": "e.g., \"retraction\", \"correction\", \"expression-of-concern\""
                                    },
                                    "label": {
                                      "type": "string"
                                    },
                                    "doi": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "date": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "source": {
                                      "type": "string",
                                      "nullable": true
                                    }
                                  }
                                }
                              },
                              "error": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                  "code": {
                                    "type": "string"
                                  },
                                  "message": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          },
                          "open_access": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                              "status": {
                                "type": "string",
                                "enum": [
                                  "open",
                                  "closed",
                                  "unknown"
                                ]
                              },
                              "oa_status": {
                                "type": "string",
                                "enum": [
                                  "gold",
                                  "green",
                                  "hybrid",
                                  "bronze",
                                  "closed"
                                ]
                              },
                              "best_url": {
                                "type": "string"
                              },
                              "pdf_url": {
                                "type": "string",
                                "description": "Direct free-PDF link when Unpaywall supplies `url_for_pdf`.",
                                "nullable": true
                              },
                              "license": {
                                "type": "string",
                                "nullable": true
                              },
                              "version": {
                                "type": "string",
                                "nullable": true
                              },
                              "error": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                  "code": {
                                    "type": "string"
                                  },
                                  "message": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          },
                          "doaj": {
                            "type": "object",
                            "description": "DOAJ (Directory of Open Access Journals) indexing status for the work's JOURNAL,\nkeyed by the container ISSN. A VENUE-level signal: `indexed` means the journal is in\nDOAJ's vetted open-access index. `not_indexed` is NOT a predatory-journal verdict —\nsubscription journals and brand-new OA titles are legitimately absent. Present only\nwhen `?checks=doaj` is requested AND the server has `ENABLE_DOAJ_CHECK=1`; otherwise\n`status` is `unknown`. (The DOAJ Seal is not surfaced — absent from the public API.)\n",
                            "additionalProperties": false,
                            "properties": {
                              "status": {
                                "type": "string",
                                "enum": [
                                  "indexed",
                                  "not_indexed",
                                  "unknown"
                                ]
                              },
                              "in_doaj": {
                                "type": "boolean"
                              },
                              "title": {
                                "type": "string",
                                "description": "DOAJ's journal title (match confirmation)."
                              },
                              "license": {
                                "type": "string",
                                "description": "Primary licence type, e.g. \"CC BY\"."
                              },
                              "issn": {
                                "type": "string",
                                "description": "ISSN matched on (normalised NNNN-NNNX)."
                              },
                              "url": {
                                "type": "string",
                                "description": "Canonical DOAJ table-of-contents URL for the journal."
                              },
                              "error": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                  "code": {
                                    "type": "string"
                                  },
                                  "message": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        }
                      },
                      "_provenance": {
                        "type": "object",
                        "description": "Sibling field on resolved items; populated only when ?provenance=1 (or =full) is set.\nAll fields beyond {transform_version, sources, resolved_at} are additive and optional —\nomitted when not applicable (e.g. fallbacks_tried is absent when the primary resolver\nwon on the first try). full_metadata appears only under ?provenance=full.\n",
                        "additionalProperties": false,
                        "required": [
                          "transform_version",
                          "sources",
                          "resolved_at"
                        ],
                        "properties": {
                          "transform_version": {
                            "type": "string",
                            "description": "Pinned dep digest mirroring x-scholar-transform-version."
                          },
                          "resolved_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "request_id": {
                            "type": "string",
                            "description": "Request correlation id (mirrors x-request-id); aligns with the verifier _provenance block."
                          },
                          "sources": {
                            "type": "array",
                            "description": "Sources that contributed the winning record (V2 emits the single winner).",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "name"
                              ],
                              "properties": {
                                "name": {
                                  "type": "string",
                                  "description": "Source service name (e.g., \"crossref\")"
                                },
                                "url": {
                                  "type": "string"
                                },
                                "fetched_at": {
                                  "type": "string",
                                  "format": "date-time",
                                  "description": "When this process fetched the record."
                                },
                                "upstream_fetched_at": {
                                  "type": "string",
                                  "format": "date-time",
                                  "description": "Upstream's own record timestamp (e.g. Crossref indexed/deposited), when available."
                                },
                                "cache": {
                                  "type": "string",
                                  "enum": [
                                    "hit",
                                    "miss",
                                    "bypass"
                                  ]
                                },
                                "role": {
                                  "type": "string",
                                  "enum": [
                                    "primary",
                                    "fallback"
                                  ],
                                  "description": "Reserved for multi-source mode; unset in V2 (sources holds only the winner)."
                                },
                                "ttl_band": {
                                  "type": "string",
                                  "enum": [
                                    "recent",
                                    "mid",
                                    "frozen"
                                  ],
                                  "description": "Cache-TTL recency band applied to this record (Phase 12g): recent (short TTL), mid, or frozen (long TTL). Present only when TTL calibration is enabled."
                                }
                              }
                            }
                          },
                          "fallbacks_tried": {
                            "type": "array",
                            "description": "Resolvers consulted before the winner; omitted when the primary won first try.",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "name",
                                "outcome"
                              ],
                              "properties": {
                                "name": {
                                  "type": "string"
                                },
                                "outcome": {
                                  "type": "string",
                                  "enum": [
                                    "won",
                                    "not_found",
                                    "error",
                                    "empty",
                                    "skipped"
                                  ]
                                },
                                "reason": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "fields_from_source": {
                            "type": "array",
                            "description": "CSL-relevant fields the upstream record populated.",
                            "items": {
                              "type": "string"
                            }
                          },
                          "fields_absent": {
                            "type": "array",
                            "description": "CSL-relevant fields the schema permits but upstream did not supply.",
                            "items": {
                              "type": "string"
                            }
                          },
                          "normalization": {
                            "type": "array",
                            "description": "Canonicalisation steps applied to the identifier(s) on this request's input.",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "rule",
                                "from",
                                "to"
                              ],
                              "properties": {
                                "rule": {
                                  "type": "string",
                                  "description": "Stable rule token, e.g. \"doi:lowercase\", \"issn:format\"."
                                },
                                "from": {
                                  "type": "string"
                                },
                                "to": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "field_provenance": {
                            "type": "object",
                            "description": "Per-field source attribution. Reserved for per-field × per-source freshness;\nsparse/omitted in V2. Object-valued so future freshness keys are additive.\n",
                            "additionalProperties": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "source"
                              ],
                              "properties": {
                                "source": {
                                  "type": "string"
                                },
                                "upstream_fetched_at": {
                                  "type": "string",
                                  "format": "date-time"
                                }
                              }
                            }
                          },
                          "full_metadata": {
                            "type": "object",
                            "description": "Rich linked-data graph; present only under ?provenance=full.",
                            "additionalProperties": false,
                            "properties": {
                              "funders": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "properties": {
                                    "name": {
                                      "type": "string"
                                    },
                                    "doi": {
                                      "type": "string"
                                    },
                                    "award": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "orcids": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "ror_ids": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "license": {
                                "type": "string",
                                "nullable": true
                              },
                              "clinical_trial_ids": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "trust_signals": {
                            "type": "object",
                            "description": "Per-signal trust summary; present only when ?checks= ran alongside\n?provenance=. Records, per requested signal, whether it was evaluated\n(a DOI was available) or skipped (no_doi), plus the resulting status.\n",
                            "additionalProperties": false,
                            "properties": {
                              "retraction": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                  "requested",
                                  "evaluated"
                                ],
                                "properties": {
                                  "requested": {
                                    "type": "boolean"
                                  },
                                  "evaluated": {
                                    "type": "boolean"
                                  },
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "ok",
                                      "retracted",
                                      "concern",
                                      "correction",
                                      "unknown"
                                    ]
                                  },
                                  "skipped_reason": {
                                    "type": "string",
                                    "enum": [
                                      "no_doi"
                                    ]
                                  }
                                }
                              },
                              "open_access": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [
                                  "requested",
                                  "evaluated"
                                ],
                                "properties": {
                                  "requested": {
                                    "type": "boolean"
                                  },
                                  "evaluated": {
                                    "type": "boolean"
                                  },
                                  "status": {
                                    "type": "string",
                                    "enum": [
                                      "open",
                                      "closed",
                                      "unknown"
                                    ]
                                  },
                                  "oa_status": {
                                    "type": "string",
                                    "enum": [
                                      "gold",
                                      "green",
                                      "hybrid",
                                      "bronze",
                                      "closed"
                                    ]
                                  },
                                  "pdf_url": {
                                    "type": "string",
                                    "nullable": true
                                  },
                                  "skipped_reason": {
                                    "type": "string",
                                    "enum": [
                                      "no_doi"
                                    ]
                                  }
                                }
                              }
                            }
                          },
                          "mode": {
                            "type": "string",
                            "enum": [
                              "strict",
                              "best-effort"
                            ],
                            "description": "Resolver mode that produced the item (Phase 12h). `strict` = fixed-order chain (today's only mode); `best-effort` reserved."
                          },
                          "selection_reason": {
                            "type": "string",
                            "enum": [
                              "static_chain_position"
                            ],
                            "description": "Why the winning source was chosen. For `strict`, always static_chain_position."
                          },
                          "container_only": {
                            "type": "boolean",
                            "description": "True when the resolved record is a journal/container, not a work — e.g.\nthe input was an ISSN/eISSN, which identifies a serial, not a paper\n(Phase 12j). Omitted (not `false`) for ordinary work records.\n"
                          },
                          "conflicts": {
                            "type": "object",
                            "description": "Cross-source verification (Phase 12a.V2b); present only under\n?provenance=conflicts AND the ENABLE_PROVENANCE_CONFLICTS server flag.\nThe winning record is cross-checked against ONE independent source\n(e.g. PubMed for a Crossref DOI; Google Books vs Open Library).\nObservational — exempt from the byte-determinism guarantee.\n",
                            "additionalProperties": false,
                            "required": [
                              "status"
                            ],
                            "properties": {
                              "checked_against": {
                                "type": "string",
                                "description": "The independent source cross-checked against (omitted when none available)."
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "agreed",
                                  "conflict",
                                  "unavailable"
                                ]
                              },
                              "skipped_reason": {
                                "type": "string",
                                "enum": [
                                  "no_secondary_source",
                                  "upstream_error",
                                  "not_found"
                                ]
                              },
                              "fields": {
                                "type": "array",
                                "description": "Field-level disagreements; present only when status is `conflict`.",
                                "items": {
                                  "type": "object",
                                  "additionalProperties": false,
                                  "required": [
                                    "field",
                                    "primary",
                                    "secondary"
                                  ],
                                  "properties": {
                                    "field": {
                                      "type": "string",
                                      "enum": [
                                        "title",
                                        "first_author",
                                        "year",
                                        "container"
                                      ]
                                    },
                                    "primary": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "required": [
                                        "source",
                                        "value"
                                      ],
                                      "properties": {
                                        "source": {
                                          "type": "string"
                                        },
                                        "value": {
                                          "oneOf": [
                                            {
                                              "type": "string"
                                            },
                                            {
                                              "type": "number"
                                            }
                                          ]
                                        }
                                      }
                                    },
                                    "secondary": {
                                      "type": "object",
                                      "additionalProperties": false,
                                      "required": [
                                        "source",
                                        "value"
                                      ],
                                      "properties": {
                                        "source": {
                                          "type": "string"
                                        },
                                        "value": {
                                          "oneOf": [
                                            {
                                              "type": "string"
                                            },
                                            {
                                              "type": "number"
                                            }
                                          ]
                                        }
                                      }
                                    },
                                    "similarity": {
                                      "type": "number",
                                      "description": "Similarity score (0–1) for fuzzy fields."
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "text": {
                  "type": "string",
                  "description": "Plain-text rendered citation(s)."
                },
                "html": {
                  "type": "string",
                  "description": "HTML rendered citation(s)."
                },
                "warnings": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "meta": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Phase 12b batch summary. Aggregate counts + a duplicate-group list for a\nrequest. Additive metadata only — it never changes the formatted output.\n`resolved` counts input lines that mapped to a work, so the buckets are\nself-consistent: `linesIn === resolved + notFound + errored + skipped`,\nand `duplicates === resolved - afterDedupe`. The same shape appears on the\nstream `done` frame. Error/skip buckets are best-effort and may differ\nslightly between /api/format (dedups failing lines) and\n/api/format/stream (counts them per occurrence).\n",
                  "properties": {
                    "linesIn": {
                      "type": "integer",
                      "description": "Total input lines."
                    },
                    "resolved": {
                      "type": "integer",
                      "description": "Input lines that resolved to a work."
                    },
                    "afterDedupe": {
                      "type": "integer",
                      "description": "Distinct works after de-duplication."
                    },
                    "duplicates": {
                      "type": "integer",
                      "description": "Collapsed duplicate lines (resolved - afterDedupe)."
                    },
                    "notFound": {
                      "type": "integer",
                      "description": "Lines that resolved to no record."
                    },
                    "errored": {
                      "type": "integer",
                      "description": "Lines that failed on an upstream/other error."
                    },
                    "skipped": {
                      "type": "integer",
                      "description": "ISSN-container / ADS-without-token lines skipped."
                    },
                    "warned": {
                      "type": "integer",
                      "description": "Count of batch warning strings."
                    },
                    "duplicateGroups": {
                      "type": "array",
                      "description": "One entry per item whose input lines collapsed (>1 source line).",
                      "items": {
                        "type": "object",
                        "properties": {
                          "idx": {
                            "type": "integer",
                            "description": "First contributing input-line index."
                          },
                          "sourceIdxs": {
                            "type": "array",
                            "items": {
                              "type": "integer"
                            },
                            "description": "All input-line indices that collapsed into this item."
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            "example": {
              "ok": true,
              "formatter": "builtin",
              "styleRequested": "vancouver",
              "styleUsed": "vancouver",
              "lang": "en-US",
              "footnote": false,
              "outputMode": "text",
              "itemsIn": 1,
              "itemsOut": 1,
              "text": "Baden LR, El Sahly HM, Essink B, et al. Efficacy and Safety of the mRNA-1273 SARS-CoV-2 Vaccine. N Engl J Med. 2021;384(5):403-416.",
              "warnings": [],
              "meta": {
                "linesIn": 1,
                "resolved": 1,
                "afterDedupe": 1,
                "duplicates": 0,
                "notFound": 0,
                "errored": 0,
                "skipped": 0,
                "warned": 0,
                "duplicateGroups": []
              }
            }
          }
        }
      },
      "BadRequest": {
        "description": "Bad Request",
        "headers": {
          "X-Request-Id": {
            "description": "Unique request correlation ID.",
            "schema": {
              "type": "string"
            }
          },
          "X-Error-Code": {
            "description": "Stable internal error code.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Instructs clients not to cache.",
            "schema": {
              "type": "string",
              "enum": [
                "no-store"
              ]
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "ok",
                "code",
                "error"
              ],
              "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
              "properties": {
                "ok": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Human-readable error message."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                }
              },
              "example": {
                "ok": false,
                "code": "BAD_REQUEST",
                "error": "Invalid input"
              }
            }
          },
          "application/problem+json": {
            "schema": {
              "type": "object",
              "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
              "required": [
                "type",
                "title",
                "status",
                "code"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "format": "uri",
                  "description": "A URI identifying the problem type (per stable error code).",
                  "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                },
                "title": {
                  "type": "string",
                  "description": "Short, human-readable summary of the problem type.",
                  "example": "Validation Error"
                },
                "status": {
                  "type": "integer",
                  "description": "HTTP status code (duplicated from the response line).",
                  "example": 400
                },
                "detail": {
                  "type": "string",
                  "description": "Human-readable explanation specific to this occurrence.",
                  "example": "Missing 'lines' (array) or 'text' (string) in body."
                },
                "instance": {
                  "type": "string",
                  "description": "Optional request correlation id (mirrors X-Request-Id)."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                  "example": "VALIDATION_ERROR"
                }
              },
              "example": {
                "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                "title": "Validation Error",
                "status": 400,
                "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                "code": "VALIDATION_ERROR"
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Unauthorized",
        "headers": {
          "X-Request-Id": {
            "description": "Unique request correlation ID.",
            "schema": {
              "type": "string"
            }
          },
          "X-Error-Code": {
            "description": "Stable internal error code.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Instructs clients not to cache.",
            "schema": {
              "type": "string",
              "enum": [
                "no-store"
              ]
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "ok",
                "code",
                "error"
              ],
              "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
              "properties": {
                "ok": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Human-readable error message."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                }
              },
              "example": {
                "ok": false,
                "code": "BAD_REQUEST",
                "error": "Invalid input"
              }
            }
          },
          "application/problem+json": {
            "schema": {
              "type": "object",
              "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
              "required": [
                "type",
                "title",
                "status",
                "code"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "format": "uri",
                  "description": "A URI identifying the problem type (per stable error code).",
                  "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                },
                "title": {
                  "type": "string",
                  "description": "Short, human-readable summary of the problem type.",
                  "example": "Validation Error"
                },
                "status": {
                  "type": "integer",
                  "description": "HTTP status code (duplicated from the response line).",
                  "example": 400
                },
                "detail": {
                  "type": "string",
                  "description": "Human-readable explanation specific to this occurrence.",
                  "example": "Missing 'lines' (array) or 'text' (string) in body."
                },
                "instance": {
                  "type": "string",
                  "description": "Optional request correlation id (mirrors X-Request-Id)."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                  "example": "VALIDATION_ERROR"
                }
              },
              "example": {
                "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                "title": "Validation Error",
                "status": 400,
                "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                "code": "VALIDATION_ERROR"
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Forbidden",
        "headers": {
          "X-Request-Id": {
            "description": "Unique request correlation ID.",
            "schema": {
              "type": "string"
            }
          },
          "X-Scholar-Mode": {
            "description": "Effective service mode (normal, read-only, maintenance).",
            "schema": {
              "type": "string",
              "enum": [
                "normal",
                "read-only",
                "maintenance"
              ]
            }
          },
          "X-Error-Code": {
            "description": "Stable internal error code.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Instructs clients not to cache.",
            "schema": {
              "type": "string",
              "enum": [
                "no-store"
              ]
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "ok",
                "code",
                "error"
              ],
              "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
              "properties": {
                "ok": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Human-readable error message."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                }
              },
              "example": {
                "ok": false,
                "code": "BAD_REQUEST",
                "error": "Invalid input"
              }
            }
          },
          "application/problem+json": {
            "schema": {
              "type": "object",
              "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
              "required": [
                "type",
                "title",
                "status",
                "code"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "format": "uri",
                  "description": "A URI identifying the problem type (per stable error code).",
                  "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                },
                "title": {
                  "type": "string",
                  "description": "Short, human-readable summary of the problem type.",
                  "example": "Validation Error"
                },
                "status": {
                  "type": "integer",
                  "description": "HTTP status code (duplicated from the response line).",
                  "example": 400
                },
                "detail": {
                  "type": "string",
                  "description": "Human-readable explanation specific to this occurrence.",
                  "example": "Missing 'lines' (array) or 'text' (string) in body."
                },
                "instance": {
                  "type": "string",
                  "description": "Optional request correlation id (mirrors X-Request-Id)."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                  "example": "VALIDATION_ERROR"
                }
              },
              "example": {
                "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                "title": "Validation Error",
                "status": 400,
                "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                "code": "VALIDATION_ERROR"
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Too Many Requests",
        "headers": {
          "X-Request-Id": {
            "description": "Unique request correlation ID.",
            "schema": {
              "type": "string"
            }
          },
          "X-RateLimit-Limit": {
            "description": "Maximum requests allowed in the current window.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          "X-RateLimit-Remaining": {
            "description": "Requests remaining in the current window.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          "X-RateLimit-Reset": {
            "description": "UTC epoch seconds when the window resets.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          "X-RateLimit-Reset-After": {
            "description": "Seconds until reset.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          "X-RateLimit-Policy": {
            "description": "Policy string (e.g., \"60;w=60, 1000;w=3600\").",
            "schema": {
              "type": "string"
            }
          },
          "Retry-After": {
            "description": "Seconds until next request allowed.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "ok",
                "code",
                "error"
              ],
              "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
              "properties": {
                "ok": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Human-readable error message."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                }
              },
              "example": {
                "ok": false,
                "code": "BAD_REQUEST",
                "error": "Invalid input"
              }
            }
          },
          "application/problem+json": {
            "schema": {
              "type": "object",
              "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
              "required": [
                "type",
                "title",
                "status",
                "code"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "format": "uri",
                  "description": "A URI identifying the problem type (per stable error code).",
                  "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                },
                "title": {
                  "type": "string",
                  "description": "Short, human-readable summary of the problem type.",
                  "example": "Validation Error"
                },
                "status": {
                  "type": "integer",
                  "description": "HTTP status code (duplicated from the response line).",
                  "example": 400
                },
                "detail": {
                  "type": "string",
                  "description": "Human-readable explanation specific to this occurrence.",
                  "example": "Missing 'lines' (array) or 'text' (string) in body."
                },
                "instance": {
                  "type": "string",
                  "description": "Optional request correlation id (mirrors X-Request-Id)."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                  "example": "VALIDATION_ERROR"
                }
              },
              "example": {
                "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                "title": "Validation Error",
                "status": 400,
                "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                "code": "VALIDATION_ERROR"
              }
            }
          }
        }
      },
      "Maintenance": {
        "description": "Service temporarily unavailable (maintenance mode).",
        "headers": {
          "X-Request-Id": {
            "description": "Unique request correlation ID.",
            "schema": {
              "type": "string"
            }
          },
          "X-Scholar-Mode": {
            "description": "Effective service mode (normal, read-only, maintenance).",
            "schema": {
              "type": "string",
              "enum": [
                "normal",
                "read-only",
                "maintenance"
              ]
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "ok",
                "code",
                "error"
              ],
              "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
              "properties": {
                "ok": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Human-readable error message."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                }
              },
              "example": {
                "ok": false,
                "code": "BAD_REQUEST",
                "error": "Invalid input"
              }
            }
          },
          "application/problem+json": {
            "schema": {
              "type": "object",
              "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
              "required": [
                "type",
                "title",
                "status",
                "code"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "format": "uri",
                  "description": "A URI identifying the problem type (per stable error code).",
                  "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                },
                "title": {
                  "type": "string",
                  "description": "Short, human-readable summary of the problem type.",
                  "example": "Validation Error"
                },
                "status": {
                  "type": "integer",
                  "description": "HTTP status code (duplicated from the response line).",
                  "example": 400
                },
                "detail": {
                  "type": "string",
                  "description": "Human-readable explanation specific to this occurrence.",
                  "example": "Missing 'lines' (array) or 'text' (string) in body."
                },
                "instance": {
                  "type": "string",
                  "description": "Optional request correlation id (mirrors X-Request-Id)."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                  "example": "VALIDATION_ERROR"
                }
              },
              "example": {
                "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                "title": "Validation Error",
                "status": 400,
                "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                "code": "VALIDATION_ERROR"
              }
            }
          }
        }
      },
      "Error": {
        "description": "Typed error (catch-all). Body is the shared `ErrorResponse` envelope and\nthe stable code is mirrored in the `X-Error-Code` response header.\n",
        "headers": {
          "X-Request-Id": {
            "description": "Unique request correlation ID.",
            "schema": {
              "type": "string"
            }
          },
          "X-Error-Code": {
            "description": "Stable internal error code.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "ok",
                "code",
                "error"
              ],
              "description": "Typed error envelope returned on 4xx/5xx protocol errors. `error` is a\nhuman-readable message. `code` is a stable, machine-readable token,\nalways present on error responses and mirrored in the `X-Error-Code`\nresponse header. Known codes: BAD_REQUEST, VALIDATION_ERROR,\nUNKNOWN_STYLE, INVALID_CONTENT_TYPE, EMPTY_BODY, MALFORMED_JSON,\nPAYLOAD_TOO_LARGE, MISSING_TITLE, RESOLVE_ERROR, READ_ONLY,\nSTREAMING_DISABLED, AUTH_MISSING, AUTH_INVALID, AUTH_DISABLED,\nLLM_SCREEN_FORBIDDEN, IDEMPOTENCY_KEY_REUSED, NOT_FOUND, RL_BLOCKED,\nMAINTENANCE, UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED,\nUPSTREAM_UNAVAILABLE, UPSTREAM_NETWORK_ERROR, ROUTE_ERROR. RL_BLOCKED\n(429) is the code actually returned when the per-IP rate limit is\nexceeded — not a generic RATE_LIMITED token.\n",
              "properties": {
                "ok": {
                  "type": "boolean",
                  "enum": [
                    false
                  ]
                },
                "error": {
                  "type": "string",
                  "description": "Human-readable error message."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (mirrors X-Error-Code)."
                }
              },
              "example": {
                "ok": false,
                "code": "BAD_REQUEST",
                "error": "Invalid input"
              }
            }
          },
          "application/problem+json": {
            "schema": {
              "type": "object",
              "description": "RFC 9457 (Problem Details for HTTP APIs) representation of an error.\nServed on any error response when the request sends\n`Accept: application/problem+json`; otherwise the default `ErrorResponse`\nenvelope is returned. The stable `code` is preserved as an extension\nmember and mirrored in the `X-Error-Code` header.\n",
              "required": [
                "type",
                "title",
                "status",
                "code"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "format": "uri",
                  "description": "A URI identifying the problem type (per stable error code).",
                  "example": "https://scholar-sidekick.com/errors/VALIDATION_ERROR"
                },
                "title": {
                  "type": "string",
                  "description": "Short, human-readable summary of the problem type.",
                  "example": "Validation Error"
                },
                "status": {
                  "type": "integer",
                  "description": "HTTP status code (duplicated from the response line).",
                  "example": 400
                },
                "detail": {
                  "type": "string",
                  "description": "Human-readable explanation specific to this occurrence.",
                  "example": "Missing 'lines' (array) or 'text' (string) in body."
                },
                "instance": {
                  "type": "string",
                  "description": "Optional request correlation id (mirrors X-Request-Id)."
                },
                "code": {
                  "type": "string",
                  "description": "Stable machine-readable error code (extension member; mirrors X-Error-Code).",
                  "example": "VALIDATION_ERROR"
                }
              },
              "example": {
                "type": "https://scholar-sidekick.com/errors/VALIDATION_ERROR",
                "title": "Validation Error",
                "status": 400,
                "detail": "Missing 'lines' (array) or 'text' (string) in body.",
                "code": "VALIDATION_ERROR"
              }
            }
          }
        }
      }
    }
  }
}
