{
  "openapi": "3.1.0",
  "info": {
    "title": "QnReady API",
    "version": "1.0.0",
    "description": "Draft answers to a security or vendor questionnaire from your own documents. You send each question with the excerpts from your documents that match it (the web app finds them in your browser); the API drafts an answer using only those excerpts, cites the excerpt numbers it used, and returns \"gap\" when they don't answer the question. Nothing is stored. A pass is required: the free pass (10 questions, from the web app at https://qnready.pages.dev/app/) or a One-File pass (150 questions + 50 re-drafts in 14 days, $199, https://qnready.pages.dev/pricing/). Drafts are suggestions: a person must review every answer. Every route is rate limited (60/min per client).",
    "contact": {
      "email": "contact@optimumtechfusion.com"
    }
  },
  "servers": [
    {
      "url": "https://qnready.pages.dev"
    }
  ],
  "paths": {
    "/api/answer": {
      "post": {
        "operationId": "answer",
        "summary": "Draft answers for 1-5 questions from your excerpts",
        "security": [
          {
            "pass": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnswerRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Draft answers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnswerResponse"
                }
              }
            }
          },
          "401": {
            "description": "RFC 9457 problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "RFC 9457 problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "RFC 9457 problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "RFC 9457 problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or allowance used: Retry-After + RateLimit headers",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "Paused (kill switch) or daily capacity reached: Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/meta": {
      "get": {
        "operationId": "meta",
        "summary": "Price, allowances, payments mode, model",
        "responses": {
          "200": {
            "description": "Meta",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "health",
        "summary": "Liveness",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or allowance used: Retry-After + RateLimit headers",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "Paused (kill switch) or daily capacity reached: Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "pass": {
        "type": "http",
        "scheme": "bearer",
        "description": "Pass token from the web app (free) or from the payment page (One-File)"
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "required": [
          "title",
          "status"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "retry_after": {
            "type": "integer"
          }
        }
      },
      "AnswerRequest": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "company": {
            "type": "string",
            "maxLength": 80,
            "description": "Your company name, used in the answer"
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5,
            "items": {
              "type": "object",
              "required": [
                "question",
                "snippets"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "maxLength": 40
                },
                "question": {
                  "type": "string",
                  "maxLength": 600
                },
                "context": {
                  "type": "string",
                  "maxLength": 400,
                  "description": "Section heading from the questionnaire"
                },
                "snippets": {
                  "type": "array",
                  "maxItems": 6,
                  "items": {
                    "type": "object",
                    "required": [
                      "text"
                    ],
                    "properties": {
                      "doc": {
                        "type": "string",
                        "maxLength": 120
                      },
                      "text": {
                        "type": "string",
                        "maxLength": 1500
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "AnswerResponse": {
        "type": "object",
        "properties": {
          "answers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "answered",
                    "partial",
                    "gap",
                    "error"
                  ]
                },
                "answer": {
                  "type": "string"
                },
                "sources": {
                  "type": "array",
                  "items": {
                    "type": "integer"
                  },
                  "description": "1-based excerpt numbers used"
                },
                "model": {
                  "type": "string"
                }
              }
            }
          },
          "remaining": {
            "type": "integer",
            "description": "Drafts left on this pass"
          }
        }
      }
    }
  }
}