{
  "openapi": "3.1.0",
  "info": {
    "title": "AIVA Claims public API",
    "version": "2026-09-19",
    "summary": "Unauthenticated endpoints of aivaclaims.com.",
    "description": "AIVA Claims is a donor-funded program of an IRS-recognized 501(c)(3) nonprofit that helps U.S. military veterans organize VA disability claim documents. This document lists only endpoints that need no account, token, or cookie. Content for agents: /llms.txt, /llms-full.txt, and a Markdown alternate of every public page (`<path>.md`, or `Accept: text/markdown`). The MCP server at /mcp is described by its own endpoint, not here.",
    "contact": {
      "name": "AIVA Claims",
      "email": "help@aivaclaims.com",
      "url": "https://aivaclaims.com/developers"
    },
    "license": {
      "name": "All rights reserved",
      "identifier": "LicenseRef-AIVA"
    }
  },
  "externalDocs": {
    "description": "Developers and AI agents",
    "url": "https://aivaclaims.com/developers"
  },
  "servers": [
    {
      "url": "https://aivaclaims.com"
    }
  ],
  "x-mcp": {
    "url": "https://aivaclaims.com/mcp",
    "transport": "streamable-http",
    "authentication": "none",
    "description": "Model Context Protocol server. POST JSON-RPC 2.0 to /mcp (Streamable HTTP); GET /mcp returns human-readable documentation. Tool and prompt schemas are served by the MCP endpoint itself (tools/list)."
  },
  "tags": [
    {
      "name": "health",
      "description": "Liveness probes."
    },
    {
      "name": "content",
      "description": "Agent-readable content."
    },
    {
      "name": "faq",
      "description": "Grounded question answering."
    },
    {
      "name": "benefits",
      "description": "Benefits Finder lookup (separate Worker on the same host)."
    },
    {
      "name": "mcp",
      "description": "Model Context Protocol."
    }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "tags": [
          "health"
        ],
        "operationId": "getHealth",
        "summary": "Service health",
        "description": "Checks D1 and R2 connectivity. 503 when the database is unreachable or critical environment variables are missing. Handler: src/worker/index.ts (app.get('/api/health')).",
        "responses": {
          "200": {
            "description": "Healthy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          },
          "503": {
            "description": "Unhealthy",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Health"
                    },
                    {
                      "$ref": "#/components/schemas/HealthMisconfigured"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/faq/ask": {
      "post": {
        "tags": [
          "faq"
        ],
        "operationId": "askFaq",
        "summary": "Ask a question grounded in AIVA's public pages",
        "description": "Streams an answer generated only from the public pages' text; questions the corpus cannot answer are redirected to support. Rate limited per IP (429 with Retry-After: 60). Handler: src/worker/faq/faq-route.ts.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FaqQuestion"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FaqQuestion"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON requests receive server-sent events (`data:` lines of {type:'text-delta',delta} then {type:'finish'} then `[DONE]`); form requests receive the complete answer as text/plain.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "stream": {
                    "value": "data: {\"type\":\"text-delta\",\"delta\":\"AIVA is\"}\n\ndata: {\"type\":\"finish\"}\n\ndata: [DONE]\n\n"
                  }
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Body is not JSON {question} or a form field, or the question is not 1 to 600 characters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body larger than 8192 bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many questions from this IP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait",
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            }
          },
          "503": {
            "description": "The assistant is unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/benefits-finder/api": {
      "post": {
        "tags": [
          "benefits"
        ],
        "operationId": "findBenefits",
        "summary": "Benefit categories for a VA disability rating",
        "description": "Served by the benefits-finder Worker (workers/benefits-finder/worker.ts, handleApi). Requires Content-Type: application/json. A browser Origin other than https://aivaclaims.com is refused (403); requests without an Origin header are accepted. Rate limited per IP. Returns an HTML fragment of official benefit categories to verify — it does not determine eligibility.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BenefitsLookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Benefit categories as an HTML fragment",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "html",
                    "success"
                  ],
                  "properties": {
                    "html": {
                      "type": "string"
                    },
                    "success": {
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, or rating not one of the allowed values",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BenefitsError"
                }
              }
            }
          },
          "403": {
            "description": "Origin header present and not https://aivaclaims.com",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BenefitsError"
                }
              }
            }
          },
          "405": {
            "description": "Method other than POST",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string",
                  "const": "POST"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BenefitsError"
                }
              }
            }
          },
          "413": {
            "description": "Body larger than 2048 bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BenefitsError"
                }
              }
            }
          },
          "415": {
            "description": "Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BenefitsError"
                }
              }
            }
          },
          "429": {
            "description": "Too many lookups from this IP",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BenefitsError"
                }
              }
            }
          },
          "503": {
            "description": "Rate limiter unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BenefitsError"
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "tags": [
          "content"
        ],
        "operationId": "getLlmsTxt",
        "summary": "llms.txt index",
        "description": "Index of public pages and agent endpoints (https://llmstxt.org/).",
        "responses": {
          "200": {
            "description": "The index",
            "headers": {
              "x-markdown-tokens": {
                "$ref": "#/components/headers/XMarkdownTokens"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "tags": [
          "content"
        ],
        "operationId": "getLlmsFullTxt",
        "summary": "Every public page as Markdown",
        "responses": {
          "200": {
            "description": "The full document",
            "headers": {
              "x-markdown-tokens": {
                "$ref": "#/components/headers/XMarkdownTokens"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/{page}.md": {
      "get": {
        "tags": [
          "content"
        ],
        "operationId": "getPageMarkdown",
        "summary": "Markdown alternate of a public page",
        "description": "The same content is returned for `GET /{page}` with `Accept: text/markdown`. The homepage alternate is /index.md.",
        "parameters": [
          {
            "name": "page",
            "in": "path",
            "required": true,
            "description": "Public page path without the leading slash.",
            "schema": {
              "type": "string",
              "enum": [
                "guides",
                "guides/amend-va-claim",
                "guides/va-payment-codes",
                "guides/va-claim-denied",
                "guides/va-claim-evidence-checklist",
                "guides/c-and-p-exam-preparation",
                "guides/va-claim-status",
                "tools/va-disability-calculator",
                "resources",
                "index",
                "faq",
                "privacy",
                "terms",
                "text-updates",
                "developers",
                "services/disability-claims",
                "services/intent-to-file",
                "services/medical-records"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The page as Markdown",
            "headers": {
              "x-markdown-tokens": {
                "$ref": "#/components/headers/XMarkdownTokens"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Not a public page"
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "content"
        ],
        "operationId": "getOpenApi",
        "summary": "This document",
        "description": "Also served at /.well-known/openapi.json.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "get": {
        "tags": [
          "mcp"
        ],
        "operationId": "getMcpDocs",
        "summary": "MCP server documentation",
        "externalDocs": {
          "url": "https://aivaclaims.com/mcp"
        },
        "responses": {
          "200": {
            "description": "Human-readable documentation of the MCP server and its tools",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "mcp"
        ],
        "operationId": "postMcp",
        "summary": "MCP Streamable HTTP endpoint",
        "description": "JSON-RPC 2.0 over MCP Streamable HTTP, stateless, no authentication. Tool schemas come from the server's own tools/list response and are not duplicated here.",
        "externalDocs": {
          "url": "https://aivaclaims.com/mcp"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response, as JSON or as a server-sent event",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON-RPC request"
          },
          "413": {
            "description": "Body too large"
          },
          "415": {
            "description": "Content-Type is not application/json"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "XMarkdownTokens": {
        "description": "Estimated token count of the body: UTF-16 length divided by 4, rounded up. An estimate, not a tokenizer.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "Health": {
        "type": "object",
        "required": [
          "db",
          "r2",
          "timestamp"
        ],
        "properties": {
          "db": {
            "type": "boolean"
          },
          "r2": {
            "type": "boolean"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix epoch milliseconds"
          }
        }
      },
      "HealthMisconfigured": {
        "type": "object",
        "required": [
          "status",
          "reason"
        ],
        "properties": {
          "status": {
            "const": "unhealthy"
          },
          "reason": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "FaqQuestion": {
        "type": "object",
        "required": [
          "question"
        ],
        "properties": {
          "question": {
            "type": "string",
            "minLength": 1,
            "maxLength": 600
          }
        }
      },
      "BenefitsLookup": {
        "type": "object",
        "required": [
          "rating"
        ],
        "additionalProperties": false,
        "properties": {
          "rating": {
            "type": "string",
            "description": "VA combined disability rating, as a string.",
            "enum": [
              "0",
              "10",
              "20",
              "30",
              "40",
              "50",
              "60",
              "70",
              "80",
              "90",
              "100"
            ]
          }
        }
      },
      "BenefitsError": {
        "type": "object",
        "required": [
          "error",
          "success"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "success": {
            "const": false
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              }
            ]
          },
          "method": {
            "type": "string"
          },
          "params": {
            "type": "object"
          }
        }
      }
    }
  }
}