{
  "openapi": "3.0.3",
  "info": {
    "title": "RxTestify — Pharmacy Benefit API",
    "description": "AI-powered pharmacy benefit testing platform that automatically extracts\nbenefit rules from plan documents and generates NCPDP-compliant F6 test claims.\n\n## Authentication\n\nMost endpoints require a Firebase ID token passed as a Bearer token:\n```\nAuthorization: Bearer <firebase_id_token>\n```\n\nAdmin-only endpoints require an `ADMIN_SECRET_KEY` passed as a `key` query parameter.\n\n## Base URL\n\n| Environment | URL |\n|---|---|\n| Production | `https://api.rxtestify.com` |\n| Local Dev | `http://localhost:8080` |\n",
    "version": "1.0.0",
    "contact": {
      "email": "info@rxtestify.com"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://api.rxtestify.com",
      "description": "Production"
    },
    {
      "url": "http://localhost:8080",
      "description": "Local development"
    }
  ],
  "tags": [
    {
      "name": "Health",
      "description": "API status and health check endpoints"
    },
    {
      "name": "Auth",
      "description": "User registration and approval workflow"
    },
    {
      "name": "Documents",
      "description": "Upload, retrieve, and delete benefit plan documents"
    },
    {
      "name": "Processing",
      "description": "AI-powered document validation and benefit extraction"
    },
    {
      "name": "Claims",
      "description": "NCPDP F6 test claim generation"
    },
    {
      "name": "Test Suites",
      "description": "Generate and manage NCPDP-compliant test scenario suites"
    },
    {
      "name": "NPI",
      "description": "Provider and pharmacy NPI lookup (no auth required)"
    },
    {
      "name": "Demo",
      "description": "Public demo request submission"
    },
    {
      "name": "Admin",
      "description": "**Internal / Admin-only endpoints.**\nThese require the `ADMIN_SECRET_KEY` passed as `?key=<secret>`.\nDo not expose the admin key publicly.\n"
    },
    {
      "name": "Prompts",
      "description": "Retrieve AI prompt templates used for benefit extraction"
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Firebase ID Token",
        "description": "Obtain a Firebase ID token after signing in with Google or Email/Password.\nPass it in the `Authorization` header as `Bearer <token>`.\n"
      },
      "AdminKey": {
        "type": "apiKey",
        "in": "query",
        "name": "key",
        "description": "Admin secret key (`ADMIN_SECRET_KEY` env var). Required for admin-only endpoints.\n"
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string",
            "example": "Missing required fields"
          },
          "message": {
            "type": "string",
            "example": "Detailed error description"
          }
        }
      },
      "ValidationObject": {
        "type": "object",
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "RegisterRequest": {
        "type": "object",
        "required": [
          "uid",
          "email"
        ],
        "properties": {
          "uid": {
            "type": "string",
            "description": "Firebase UID",
            "example": "abc123xyz"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "user@example.com"
          },
          "displayName": {
            "type": "string",
            "example": "Jane Smith"
          },
          "provider": {
            "type": "string",
            "enum": [
              "google",
              "password",
              "email"
            ],
            "example": "google"
          }
        }
      },
      "RegisterResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected"
            ],
            "example": "pending"
          },
          "isNew": {
            "type": "boolean",
            "description": "Whether this is a newly created account",
            "example": true
          },
          "message": {
            "type": "string",
            "example": "Registration successful. Awaiting admin approval."
          }
        }
      },
      "AuthStatusResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected"
            ]
          },
          "displayName": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          }
        }
      },
      "DocumentRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Firestore document ID",
            "example": "abc123"
          },
          "displayName": {
            "type": "string",
            "example": "ACME Health Plan 2025"
          },
          "filename": {
            "type": "string",
            "example": "plan-document.pdf"
          },
          "fileType": {
            "type": "string",
            "enum": [
              "application/pdf",
              "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
              "application/msword",
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
              "application/vnd.ms-excel",
              "application/json"
            ],
            "example": "application/pdf"
          },
          "fileSize": {
            "type": "integer",
            "description": "File size in bytes",
            "example": 204800
          },
          "status": {
            "type": "string",
            "enum": [
              "uploaded",
              "processing",
              "completed",
              "failed",
              "deleted",
              "test_suite_generated"
            ],
            "example": "completed"
          },
          "uploadDate": {
            "type": "string",
            "format": "date-time"
          },
          "storageUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://storage.googleapis.com/..."
          },
          "extractedText": {
            "type": "string",
            "nullable": true,
            "description": "Raw text extracted from the document (available after processing)"
          },
          "aiAnalysis": {
            "type": "object",
            "nullable": true,
            "description": "Structured benefit data extracted by Claude AI"
          },
          "testSuiteId": {
            "type": "string",
            "nullable": true,
            "description": "ID of the most recent test suite generated from this document"
          },
          "userId": {
            "type": "string",
            "description": "Firebase UID of the owning user"
          },
          "description": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "DocumentUploadRequest": {
        "type": "object",
        "required": [
          "file",
          "filename",
          "fileType",
          "userId"
        ],
        "properties": {
          "file": {
            "type": "string",
            "format": "byte",
            "description": "Base64-encoded file content (max 10 MB)",
            "example": "JVBERi0xLjQKJe..."
          },
          "filename": {
            "type": "string",
            "example": "plan-document.pdf"
          },
          "fileType": {
            "type": "string",
            "enum": [
              "application/pdf",
              "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
              "application/msword",
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
              "application/vnd.ms-excel",
              "application/json"
            ],
            "example": "application/pdf"
          },
          "userId": {
            "type": "string",
            "description": "Firebase UID of the uploading user",
            "example": "uid-abc123"
          },
          "displayName": {
            "type": "string",
            "description": "Human-readable label for the document (defaults to filename)",
            "example": "ACME Plan 2025"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Medicare Part D formulary document"
          }
        }
      },
      "DocumentUploadResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "message": {
            "type": "string",
            "example": "Document uploaded successfully. Processing started in background."
          },
          "data": {
            "type": "object",
            "properties": {
              "documentId": {
                "type": "string",
                "example": "doc-xyz789"
              },
              "filename": {
                "type": "string"
              },
              "fileType": {
                "type": "string"
              },
              "fileSize": {
                "type": "integer"
              },
              "status": {
                "type": "string",
                "example": "uploaded"
              },
              "storageUrl": {
                "type": "string",
                "format": "uri"
              },
              "uploadDate": {
                "type": "string",
                "format": "date-time"
              },
              "processingStatus": {
                "type": "string",
                "example": "started"
              },
              "note": {
                "type": "string",
                "example": "Poll /api/documents/[id] to check processing status"
              }
            }
          }
        }
      },
      "ValidateDocumentRequest": {
        "type": "object",
        "required": [
          "documentId",
          "userId"
        ],
        "properties": {
          "documentId": {
            "type": "string",
            "example": "doc-xyz789"
          },
          "userId": {
            "type": "string",
            "example": "uid-abc123"
          }
        }
      },
      "ValidateDocumentResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "validation": {
                "type": "object",
                "properties": {
                  "canProceed": {
                    "type": "boolean"
                  },
                  "content": {
                    "type": "object",
                    "description": "Content readability assessment"
                  },
                  "size": {
                    "type": "object",
                    "description": "File size constraints"
                  },
                  "cost": {
                    "type": "object",
                    "description": "Estimated AI processing cost"
                  },
                  "rateLimit": {
                    "type": "object",
                    "description": "Rate limit status for the user"
                  },
                  "warnings": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "errors": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ProcessDocumentRequest": {
        "type": "object",
        "required": [
          "documentId",
          "userId"
        ],
        "properties": {
          "documentId": {
            "type": "string",
            "example": "doc-xyz789"
          },
          "userId": {
            "type": "string",
            "example": "uid-abc123"
          },
          "customPrompt": {
            "type": "string",
            "nullable": true,
            "description": "Override the default benefit extraction prompt"
          },
          "category": {
            "type": "string",
            "nullable": true,
            "enum": [
              "comprehensive",
              "costShares",
              "accumulators",
              "drugCoverage",
              "formularyTiering",
              "utilizationManagement"
            ],
            "description": "Which category of benefits to extract (defaults to comprehensive)",
            "example": "comprehensive"
          }
        }
      },
      "ProcessDocumentResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "analysis": {
            "type": "object",
            "description": "Structured benefit data extracted by Claude"
          },
          "metadata": {
            "type": "object",
            "properties": {
              "tokenCount": {
                "type": "integer"
              },
              "model": {
                "type": "string",
                "example": "claude-3-5-sonnet-20241022"
              },
              "processingTime": {
                "type": "integer",
                "description": "Processing time in milliseconds"
              }
            }
          },
          "promptUsed": {
            "type": "string",
            "description": "The prompt category used for extraction"
          },
          "category": {
            "type": "string"
          }
        }
      },
      "ClaimInputs": {
        "type": "object",
        "required": [
          "ndc",
          "quantityDispensed",
          "daysSupply",
          "prescriberID",
          "pharmacyNPI",
          "ingredientCost",
          "dispensingFee"
        ],
        "properties": {
          "binNumber": {
            "type": "string",
            "maxLength": 6,
            "example": "610097"
          },
          "pcn": {
            "type": "string",
            "maxLength": 10,
            "example": "TESTPCN"
          },
          "groupId": {
            "type": "string",
            "maxLength": 15,
            "example": "GRP001"
          },
          "cardholderID": {
            "type": "string",
            "maxLength": 20,
            "example": "CH12345678"
          },
          "personCode": {
            "type": "string",
            "maxLength": 3,
            "example": "01"
          },
          "patientRelationship": {
            "type": "string",
            "enum": [
              "0",
              "1",
              "2",
              "3",
              "4"
            ],
            "description": "0=Not Specified, 1=Cardholder, 2=Spouse, 3=Child, 4=Other",
            "example": "1"
          },
          "dateOfBirth": {
            "type": "string",
            "pattern": "^\\d{8}$",
            "description": "CCYYMMDD format",
            "example": "19800115"
          },
          "patientGender": {
            "type": "string",
            "enum": [
              "0",
              "1",
              "2"
            ],
            "description": "0=Not Specified, 1=Male, 2=Female",
            "example": "1"
          },
          "patientFirstName": {
            "type": "string",
            "maxLength": 12,
            "example": "JOHN"
          },
          "patientLastName": {
            "type": "string",
            "maxLength": 15,
            "example": "DOE"
          },
          "patientStreetAddress": {
            "type": "string",
            "maxLength": 30,
            "example": "123 MAIN ST"
          },
          "patientCity": {
            "type": "string",
            "maxLength": 20,
            "example": "COLUMBUS"
          },
          "patientState": {
            "type": "string",
            "maxLength": 2,
            "example": "OH"
          },
          "patientZip": {
            "type": "string",
            "maxLength": 15,
            "example": "43215"
          },
          "ndc": {
            "type": "string",
            "pattern": "^\\d{11}$",
            "description": "11-digit NDC (no dashes)",
            "example": "00093721656"
          },
          "quantityDispensed": {
            "type": "number",
            "format": "float",
            "example": 30
          },
          "daysSupply": {
            "type": "integer",
            "example": 30
          },
          "dawCode": {
            "type": "string",
            "enum": [
              "0",
              "1",
              "2",
              "3",
              "4",
              "5",
              "6",
              "7",
              "8",
              "9"
            ],
            "description": "Dispense As Written code",
            "example": "0"
          },
          "prescriberID": {
            "type": "string",
            "description": "NPI of prescriber",
            "maxLength": 15,
            "example": "1234567890"
          },
          "prescriberLastName": {
            "type": "string",
            "maxLength": 15,
            "example": "SMITH"
          },
          "prescriberFirstName": {
            "type": "string",
            "maxLength": 12,
            "example": "JOHN"
          },
          "pharmacyNPI": {
            "type": "string",
            "maxLength": 10,
            "example": "9876543210"
          },
          "pharmacyName": {
            "type": "string",
            "maxLength": 30,
            "example": "WALGREENS PHARMACY"
          },
          "pharmacyStreetAddress": {
            "type": "string",
            "maxLength": 30,
            "example": "456 ELM AVE"
          },
          "pharmacyCity": {
            "type": "string",
            "maxLength": 20,
            "example": "COLUMBUS"
          },
          "pharmacyState": {
            "type": "string",
            "maxLength": 2,
            "example": "OH"
          },
          "pharmacyZip": {
            "type": "string",
            "maxLength": 15,
            "example": "43201"
          },
          "ingredientCost": {
            "type": "number",
            "format": "float",
            "description": "Ingredient cost in dollars",
            "example": 25.5
          },
          "dispensingFee": {
            "type": "number",
            "format": "float",
            "description": "Dispensing fee in dollars",
            "example": 1.75
          },
          "pharmacyType": {
            "type": "string",
            "enum": [
              "retail",
              "mailOrder",
              "specialty",
              "longTermCare"
            ],
            "example": "retail"
          }
        }
      },
      "GenerateF6ClaimRequest": {
        "type": "object",
        "required": [
          "benefitId",
          "claimInputs"
        ],
        "properties": {
          "benefitId": {
            "type": "string",
            "description": "ID of the processed document/benefit to use as context",
            "example": "doc-xyz789"
          },
          "claimInputs": {
            "$ref": "#/components/schemas/ClaimInputs"
          },
          "options": {
            "type": "object",
            "description": "Optional generation overrides",
            "properties": {
              "format": {
                "type": "string",
                "enum": [
                  "F6"
                ],
                "default": "F6"
              }
            }
          }
        }
      },
      "GenerateF6ClaimResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "claimId": {
            "type": "string",
            "example": "clm-abc123"
          },
          "format": {
            "type": "string",
            "example": "F6"
          },
          "claim": {
            "type": "object",
            "description": "Fully populated NCPDP F6 formatted claim object"
          },
          "metadata": {
            "type": "object",
            "properties": {
              "validation": {
                "$ref": "#/components/schemas/ValidationObject"
              },
              "tokenCount": {
                "type": "integer"
              },
              "model": {
                "type": "string"
              }
            }
          },
          "downloadUrl": {
            "type": "string",
            "format": "uri",
            "nullable": true
          }
        }
      },
      "TestScenario": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "TS-001"
          },
          "description": {
            "type": "string",
            "example": "Tier 1 generic drug — expected patient pays $10 copay"
          },
          "claimInputs": {
            "$ref": "#/components/schemas/ClaimInputs"
          },
          "expectedResult": {
            "type": "string",
            "enum": [
              "approved",
              "rejected",
              "partially_approved"
            ],
            "example": "approved"
          },
          "expectedPatientPay": {
            "type": "number",
            "nullable": true
          },
          "expectedPlanPay": {
            "type": "number",
            "nullable": true
          },
          "category": {
            "type": "string",
            "example": "formulary_tier_1"
          },
          "notes": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "TestSuiteRecord": {
        "type": "object",
        "properties": {
          "testSuiteId": {
            "type": "string",
            "example": "TS-1234567890"
          },
          "planName": {
            "type": "string",
            "example": "ACME Health Plan 2025"
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "totalScenarios": {
            "type": "integer"
          },
          "scenarios": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestScenario"
            }
          },
          "validation": {
            "$ref": "#/components/schemas/ValidationObject"
          },
          "confidence": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 1,
            "example": 0.95
          }
        }
      },
      "GenerateTestSuiteRequest": {
        "type": "object",
        "required": [
          "benefitId"
        ],
        "properties": {
          "benefitId": {
            "type": "string",
            "description": "ID of the processed document to generate scenarios from",
            "example": "doc-xyz789"
          },
          "mode": {
            "type": "string",
            "enum": [
              "comprehensive",
              "quick",
              "edgeCase"
            ],
            "default": "comprehensive",
            "description": "- `comprehensive`: Full coverage across all benefit categories\n- `quick`: Smaller set of high-priority scenarios\n- `edgeCase`: Focus on boundary and edge conditions\n"
          },
          "options": {
            "type": "object",
            "description": "Optional overrides passed to the generator",
            "properties": {
              "maxTokens": {
                "type": "integer",
                "example": 4000
              }
            }
          },
          "correctedTestSuite": {
            "$ref": "#/components/schemas/TestSuiteRecord",
            "nullable": true,
            "description": "Submit a manually corrected test suite to save it (replaces AI generation)"
          },
          "originalResponseId": {
            "type": "string",
            "nullable": true,
            "description": "ID of the raw AI response being corrected"
          }
        }
      },
      "GenerateTestSuiteResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "testSuiteId": {
            "type": "string",
            "description": "Firestore ID of the stored test suite"
          },
          "testSuite": {
            "$ref": "#/components/schemas/TestSuiteRecord"
          },
          "message": {
            "type": "string",
            "example": "Generated 12 test scenarios"
          },
          "summary": {
            "type": "object",
            "properties": {
              "totalScenarios": {
                "type": "integer"
              },
              "mode": {
                "type": "string"
              },
              "confidence": {
                "type": "number"
              },
              "validation": {
                "$ref": "#/components/schemas/ValidationObject"
              },
              "updated": {
                "type": "boolean",
                "description": "True if an existing test suite was updated"
              },
              "correctionCount": {
                "type": "integer"
              }
            }
          }
        }
      },
      "NpiRecord": {
        "type": "object",
        "properties": {
          "npi": {
            "type": "string",
            "pattern": "^\\d{10}$",
            "example": "1234567890"
          },
          "type": {
            "type": "string",
            "enum": [
              "prescriber",
              "pharmacy"
            ]
          },
          "name": {
            "type": "string",
            "example": "Smith, John MD"
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "specialty": {
            "type": "string",
            "nullable": true,
            "example": "Family Practice"
          },
          "address": {
            "type": "object",
            "properties": {
              "street": {
                "type": "string"
              },
              "city": {
                "type": "string"
              },
              "state": {
                "type": "string"
              },
              "zip": {
                "type": "string"
              }
            }
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "mailOrder": {
            "type": "boolean",
            "nullable": true,
            "description": "Present only for pharmacy records"
          }
        }
      },
      "DemoRequestBody": {
        "type": "object",
        "required": [
          "name",
          "email",
          "description"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "example": "Jane Smith"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "jane@acmehealth.com"
          },
          "phone": {
            "type": "string",
            "nullable": true,
            "example": "+1-614-555-0123"
          },
          "description": {
            "type": "string",
            "minLength": 10,
            "example": "We are a mid-size PBM looking to automate F6 benefit testing."
          }
        }
      },
      "DemoRequestRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "contacted",
              "demo_scheduled",
              "demo_completed",
              "follow_up",
              "closed"
            ]
          },
          "submittedAt": {
            "type": "string",
            "format": "date-time"
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "nextFollowUpDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "closedReason": {
            "type": "string",
            "enum": [
              "won",
              "lost",
              "not_interested",
              "no_budget",
              "other"
            ],
            "nullable": true
          },
          "closedNote": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "UpdateDemoRequestBody": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "new",
              "contacted",
              "demo_scheduled",
              "demo_completed",
              "follow_up",
              "closed"
            ]
          },
          "note": {
            "type": "string",
            "description": "Append a new note to this record"
          },
          "nextFollowUpDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "closedReason": {
            "type": "string",
            "enum": [
              "won",
              "lost",
              "not_interested",
              "no_budget",
              "other"
            ],
            "nullable": true
          },
          "closedNote": {
            "type": "string",
            "nullable": true
          }
        }
      }
    }
  },
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Health check",
        "description": "Returns 200 OK. Used by Cloud Run / load balancers to verify the service is running.",
        "operationId": "healthCheck",
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "API info & endpoint list",
        "description": "Returns API version, status, and a list of all available endpoints.",
        "operationId": "apiInfo",
        "responses": {
          "200": {
            "description": "API information",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string",
                      "example": "RxTestify API is running"
                    },
                    "version": {
                      "type": "string",
                      "example": "1.0.0"
                    },
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/register": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Register a new user",
        "description": "Called automatically after Firebase sign-in. Creates a user record in Firestore\nwith `status: pending`. A notification email is sent to the admin for approval.\n",
        "operationId": "registerUser",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registration successful (existing user returned)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterResponse"
                }
              }
            }
          },
          "201": {
            "description": "New user created, pending admin approval",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/status": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Check user approval status",
        "description": "Poll this endpoint to determine if a user's account has been approved by an admin.",
        "operationId": "getAuthStatus",
        "parameters": [
          {
            "name": "uid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Firebase UID of the user",
            "example": "abc123xyz"
          }
        ],
        "responses": {
          "200": {
            "description": "User status returned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthStatusResponse"
                }
              }
            }
          },
          "404": {
            "description": "User not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/approve": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "Admin one-click approve or reject user",
        "description": "**Admin-only.** Sent as an email link to the admin. Approves or rejects\na pending user account. Sends a notification email to the user.\n\n> ⚠️ Requires the `ADMIN_SECRET_KEY` as `?key=` query parameter.\n",
        "operationId": "approveUser",
        "x-internal": true,
        "security": [
          {
            "AdminKey": []
          }
        ],
        "parameters": [
          {
            "name": "uid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Firebase UID of the user to approve or reject"
          },
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "approve",
                "reject"
              ]
            },
            "description": "Action to perform"
          },
          {
            "name": "key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Admin secret key"
          }
        ],
        "responses": {
          "200": {
            "description": "HTML confirmation page rendered to admin",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Invalid admin key"
          },
          "404": {
            "description": "User not found"
          }
        }
      }
    },
    "/api/documents/upload": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Upload a benefit plan document",
        "description": "Accepts PDF, DOCX, XLSX, or HPMS JSON files up to **10 MB**.\nThe file must be base64-encoded in the request body.\n\n**Processing is asynchronous** — the endpoint returns immediately after\nupload. AI extraction runs in the background. Poll `GET /api/documents/{id}`\nto monitor `status`.\n",
        "operationId": "uploadDocument",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentUploadRequest"
              },
              "example": {
                "file": "JVBERi0xLjQKJe...",
                "filename": "plan-document.pdf",
                "fileType": "application/pdf",
                "userId": "uid-abc123",
                "displayName": "ACME Health Plan 2025"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document uploaded; background processing started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentUploadResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed (invalid type, size, missing fields)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized — missing or invalid Firebase token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error during upload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/documents": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "List user's documents",
        "description": "Returns all non-deleted documents belonging to the authenticated user.",
        "operationId": "listDocuments",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Firebase UID — must match the authenticated user"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 100
            },
            "description": "Maximum number of documents to return"
          }
        ],
        "responses": {
          "200": {
            "description": "List of documents",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "documents": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DocumentRecord"
                          }
                        },
                        "count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/documents/{id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Get a document by ID",
        "description": "Returns full document record including extracted text and AI analysis (if available).",
        "operationId": "getDocument",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Document ID",
            "example": "doc-xyz789"
          }
        ],
        "responses": {
          "200": {
            "description": "Document record",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/DocumentRecord"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden — document belongs to another user"
          },
          "404": {
            "description": "Document not found"
          }
        }
      },
      "delete": {
        "tags": [
          "Documents"
        ],
        "summary": "Delete (soft-delete) a document",
        "description": "Marks the document as `status: deleted`. The record is retained in Firestore\nbut will no longer appear in list queries.\n",
        "operationId": "deleteDocument",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Document ID"
          },
          {
            "name": "userId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Firebase UID — must match the owning user"
          }
        ],
        "responses": {
          "200": {
            "description": "Document deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string",
                      "example": "Document deleted successfully"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Document not found"
          }
        }
      }
    },
    "/api/validate-document": {
      "post": {
        "tags": [
          "Processing"
        ],
        "summary": "Validate document before AI processing",
        "description": "Pre-checks a document for:\n- Content readability (non-empty, parseable)\n- Size compliance (≤ 10 MB)\n- Estimated AI processing cost\n- User rate limit availability\n\nReturns `canProceed: true` if the document is safe to process.\n",
        "operationId": "validateDocument",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ValidateDocumentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateDocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing required fields"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Document not found"
          }
        }
      }
    },
    "/api/process-document": {
      "post": {
        "tags": [
          "Processing"
        ],
        "summary": "Extract benefits from document using AI",
        "description": "Sends the extracted document text to Claude for structured benefit extraction.\nThe result is stored back on the document record as `aiAnalysis`.\n\n**Note:** This endpoint calls the Claude API and may take 15–60 seconds depending\non document size. Consider calling `GET /api/validate-document` first.\n",
        "operationId": "processDocument",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProcessDocumentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "AI analysis complete",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessDocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing fields or document not yet uploaded"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Document not found"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Claude API error"
          }
        }
      }
    },
    "/api/generate-f6-claim": {
      "post": {
        "tags": [
          "Claims"
        ],
        "summary": "Generate an NCPDP F6 test claim",
        "description": "Generates a fully populated NCPDP F6 (version 6.x) test claim using:\n- Extracted benefit rules from the specified document\n- Claim inputs provided in the request body\n\nThe generated claim is stored in the `claims` Firestore collection.\n",
        "operationId": "generateF6Claim",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateF6ClaimRequest"
              },
              "example": {
                "benefitId": "doc-xyz789",
                "claimInputs": {
                  "binNumber": "610097",
                  "pcn": "TESTPCN",
                  "groupId": "GRP001",
                  "cardholderID": "CH12345678",
                  "personCode": "01",
                  "dateOfBirth": "19800115",
                  "ndc": "00093721656",
                  "quantityDispensed": 30,
                  "daysSupply": 30,
                  "dawCode": "0",
                  "prescriberID": "1234567890",
                  "prescriberLastName": "SMITH",
                  "pharmacyNPI": "9876543210",
                  "pharmacyName": "WALGREENS PHARMACY",
                  "pharmacyState": "OH",
                  "ingredientCost": 25.5,
                  "dispensingFee": 1.75,
                  "pharmacyType": "retail"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "F6 claim generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenerateF6ClaimResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing claim inputs"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Benefit document not found"
          },
          "500": {
            "description": "Claim generation failed"
          }
        }
      }
    },
    "/api/test-suites": {
      "get": {
        "tags": [
          "Test Suites"
        ],
        "summary": "List test suites for a document",
        "description": "Returns all test suites generated from a specific benefit document.",
        "operationId": "listTestSuites",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "documentId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the source benefit document",
            "example": "doc-xyz789"
          }
        ],
        "responses": {
          "200": {
            "description": "List of test suites",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "testSuites": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "benefitId": {
                                "type": "string"
                              },
                              "mode": {
                                "type": "string"
                              },
                              "scenarioCount": {
                                "type": "integer"
                              },
                              "confidence": {
                                "type": "number"
                              },
                              "generatedAt": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "corrected": {
                                "type": "boolean"
                              }
                            }
                          }
                        },
                        "count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/generate-test-suite": {
      "post": {
        "tags": [
          "Test Suites"
        ],
        "summary": "Generate a test suite from a benefit document",
        "description": "Uses Claude AI to generate a set of NCPDP-compliant test scenarios based on\nthe extracted benefit rules of a processed document.\n\nYou can also submit a `correctedTestSuite` to save a manually edited version\nrather than triggering a new AI generation.\n",
        "operationId": "generateTestSuite",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateTestSuiteRequest"
              },
              "example": {
                "benefitId": "doc-xyz789",
                "mode": "comprehensive"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Test suite generated (or updated) successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenerateTestSuiteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Benefit extraction not complete, or missing fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden — document belongs to another user"
          },
          "404": {
            "description": "Document not found"
          },
          "500": {
            "description": "Test suite generation failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    },
                    "responseId": {
                      "type": "string",
                      "nullable": true,
                      "description": "ID of the raw AI response (use to review/correct)"
                    },
                    "canReview": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/test-suite-responses/{id}": {
      "get": {
        "tags": [
          "Test Suites"
        ],
        "summary": "Get raw AI response for a test suite",
        "description": "Returns the raw Claude API response that was used to generate a test suite.\nUseful for reviewing parse errors or inspecting the model's raw output.\n",
        "operationId": "getTestSuiteResponse",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Test suite response ID",
            "example": "resp-abc123"
          }
        ],
        "responses": {
          "200": {
            "description": "Raw response record",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "response": {
                      "type": "object",
                      "properties": {
                        "responseId": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "pending",
                            "success",
                            "parse_error",
                            "failed"
                          ]
                        },
                        "mode": {
                          "type": "string"
                        },
                        "rawResponse": {
                          "type": "string",
                          "description": "Raw text returned by Claude"
                        },
                        "parseError": {
                          "type": "string",
                          "nullable": true
                        },
                        "parsedTestSuite": {
                          "$ref": "#/components/schemas/TestSuiteRecord",
                          "nullable": true
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Response not found"
          }
        }
      }
    },
    "/api/npi/lookup": {
      "get": {
        "tags": [
          "NPI"
        ],
        "summary": "Look up a specific NPI",
        "description": "Returns provider or pharmacy details for the given 10-digit NPI.\n\n**Lookup order:** in-memory seed data → Firestore cache → NPPES API.\n",
        "operationId": "npiLookup",
        "parameters": [
          {
            "name": "npi",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^\\d{10}$"
            },
            "description": "10-digit NPI number",
            "example": "1234567890"
          }
        ],
        "responses": {
          "200": {
            "description": "NPI record found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/NpiRecord"
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "seed",
                        "cache",
                        "nppes_api"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing NPI parameter"
          },
          "404": {
            "description": "NPI not found"
          }
        }
      }
    },
    "/api/npi/search": {
      "get": {
        "tags": [
          "NPI"
        ],
        "summary": "Search providers or pharmacies by name",
        "description": "Search the NPI registry by name and optional filters.\n\n**Prescriber search:** use `type=prescriber` with `firstName` / `lastName`.\n\n**Pharmacy search:** use `type=pharmacy` with `name`.\n",
        "operationId": "npiSearch",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "prescriber",
                "pharmacy"
              ]
            },
            "description": "Entity type to search for"
          },
          {
            "name": "firstName",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "First name (prescriber only)",
            "example": "John"
          },
          {
            "name": "lastName",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Last name (prescriber only)",
            "example": "Smith"
          },
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Organization name (pharmacy only)",
            "example": "Walgreens"
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 2
            },
            "description": "Two-letter state abbreviation filter",
            "example": "OH"
          }
        ],
        "responses": {
          "200": {
            "description": "Search results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NpiRecord"
                      }
                    },
                    "count": {
                      "type": "integer"
                    },
                    "filters": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing required parameters"
          }
        }
      }
    },
    "/api/npi/random": {
      "get": {
        "tags": [
          "NPI"
        ],
        "summary": "Get a random NPI record",
        "description": "Returns a random prescriber or pharmacy NPI matching the given filters.",
        "operationId": "npiRandom",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "prescriber",
                "pharmacy"
              ]
            }
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 2
            },
            "description": "Two-letter state abbreviation",
            "example": "OH"
          },
          {
            "name": "mailOrder",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Filter pharmacy by mail-order status (pharmacy only)"
          },
          {
            "name": "specialty",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Filter pharmacy by specialty designation (pharmacy only)"
          }
        ],
        "responses": {
          "200": {
            "description": "Random NPI record",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/NpiRecord"
                    },
                    "filters": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/demo-request": {
      "post": {
        "tags": [
          "Demo"
        ],
        "summary": "Submit a demo request",
        "description": "Public endpoint — no authentication required. Submits a request for an RxTestify\nproduct demo. An email notification is sent to `info@rxtestify.com`.\n",
        "operationId": "submitDemoRequest",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DemoRequestBody"
              },
              "example": {
                "name": "Jane Smith",
                "email": "jane@acmehealth.com",
                "phone": "+1-614-555-0123",
                "description": "We are a mid-size PBM looking to automate F6 benefit testing."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Demo request submitted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string",
                      "example": "Demo request submitted successfully"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "requestId": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation failed (name too short, invalid email, description too short)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error saving request or sending email"
          }
        }
      }
    },
    "/api/admin/demo-requests": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "List all demo requests",
        "description": "**Admin-only.** Returns all demo request records from Firestore.\n\n> ⚠️ Requires `?key=<ADMIN_SECRET_KEY>`.\n",
        "operationId": "listDemoRequests",
        "x-internal": true,
        "security": [
          {
            "AdminKey": []
          }
        ],
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Admin secret key"
          }
        ],
        "responses": {
          "200": {
            "description": "All demo requests",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DemoRequestRecord"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid admin key"
          }
        }
      }
    },
    "/api/admin/demo-requests/{id}": {
      "patch": {
        "tags": [
          "Admin"
        ],
        "summary": "Update a demo request",
        "description": "**Admin-only.** Update the status, add a note, set a follow-up date, or close\na demo request with a reason.\n\n> ⚠️ Requires `?key=<ADMIN_SECRET_KEY>`.\n",
        "operationId": "updateDemoRequest",
        "x-internal": true,
        "security": [
          {
            "AdminKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Demo request ID"
          },
          {
            "name": "key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Admin secret key"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDemoRequestBody"
              },
              "example": {
                "status": "contacted",
                "note": "Left voicemail. Will follow up Friday.",
                "nextFollowUpDate": "2025-02-21"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Demo request updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "string"
                    },
                    "updated": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "List of field names that were updated"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid status or missing required fields"
          },
          "401": {
            "description": "Invalid admin key"
          },
          "404": {
            "description": "Demo request not found"
          }
        }
      }
    },
    "/api/prompts/benefit-analysis": {
      "get": {
        "tags": [
          "Prompts"
        ],
        "summary": "Get benefit analysis prompt templates",
        "description": "Returns the map of named prompt templates used by the AI benefit extraction pipeline.\nThese can be inspected to understand what the model is asked to extract, or used\nas references when submitting `customPrompt` in `/api/process-document`.\n",
        "operationId": "getBenefitAnalysisPrompts",
        "responses": {
          "200": {
            "description": "Prompt templates map",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "string"
                  },
                  "description": "Key-value map of prompt name → prompt text"
                }
              }
            }
          }
        }
      }
    }
  }
}