openapi: 3.1.0
info:
  title: CharitySense API
  version: 3.0.0
  description: >
    Canonical read API for CharitySense nonprofit profiles compiled from data_overlay.
    Responses use UpperCamelCase fields and return the documented resource directly.
  contact:
    name: CharitySense
    email: mazhar@charitysense.com
    url: https://data.charitysense.com/contact
servers:
  - url: https://data.charitysense.com
tags:
  - name: Profiles
    description: Canonical overlay profile and filing resources.
  - name: Discovery
    description: Identity search and related-organization discovery.
  - name: Dataset
    description: Service health and published dataset statistics.
  - name: Forms
    description: Forms used by the CharitySense site and agent integrations.
  - name: Assistant
    description: First-party and API-key assistant operations.
paths:
  /api/v2/health:
    get:
      tags: [Dataset]
      operationId: getHealth
      summary: Check API liveness.
      responses:
        "200":
          description: The API process is healthy.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Health"
        "503":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/stats:
    get:
      tags: [Dataset]
      operationId: getStats
      summary: Get published dataset statistics.
      responses:
        "200":
          description: Published corpus totals and freshness metadata.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Stats"
        "503":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/top-lists:
    get:
      tags: [Discovery]
      operationId: getTopLists
      summary: Get this week's cause-based top 10 lists with live ratings.
      responses:
        "200":
          description: Six current discovery lists. Profiles without a current live rating are excluded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TopLists"
        "503":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/search:
    get:
      tags: [Discovery]
      operationId: searchOrganizations
      summary: Search canonical organization identity or discovery indexes.
      parameters:
        - name: Query
          in: query
          required: true
          description: Organization name, EIN, alias, cause, or donor intent.
          schema:
            type: string
            minLength: 1
        - name: Mode
          in: query
          description: Identity uses deterministic identity fields; Discovery includes semantic cause text.
          schema:
            type: string
            enum: [Identity, Discovery]
            default: Identity
        - name: Cursor
          in: query
          description: One-based Typesense result page.
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: Limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
        - name: State
          in: query
          schema:
            type: string
        - name: Cause
          in: query
          schema:
            type: string
        - name: MinRevenue
          in: query
          schema:
            type: number
        - name: Sort
          in: query
          schema:
            type: string
            enum: [Relevance, Revenue, Assets, Recent]
            default: Relevance
      responses:
        "200":
          description: Search results from a canonical search alias.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchResults"
        "422":
          $ref: "#/components/responses/ErrorResponse"
        "503":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/charity/{ein}/page:
    get:
      tags: [Profiles]
      operationId: getCharityPage
      summary: Get the bounded first-paint profile payload.
      parameters:
        - $ref: "#/components/parameters/Ein"
        - $ref: "#/components/parameters/Form"
        - $ref: "#/components/parameters/Year"
      responses:
        "200":
          description: Selected form context, hero, live verdict, and section manifest.
          headers:
            ETag:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CharityPage"
        "404":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/charity/{ein}/sections/{SectionId}:
    get:
      tags: [Profiles]
      operationId: getCharitySection
      summary: Get one section advertised by the page manifest.
      parameters:
        - $ref: "#/components/parameters/Ein"
        - name: SectionId
          in: path
          required: true
          description: Section Id returned by CharityPage.Sections.
          schema:
            type: string
        - $ref: "#/components/parameters/Form"
        - $ref: "#/components/parameters/Year"
        - $ref: "#/components/parameters/OpaqueCursor"
        - $ref: "#/components/parameters/SectionLimit"
      responses:
        "200":
          description: Section data with canonical evidence references.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CharitySection"
        "404":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/charity/{ein}/filings:
    get:
      tags: [Profiles]
      operationId: getCharityFilings
      summary: List filing metadata for one form context.
      parameters:
        - $ref: "#/components/parameters/Ein"
        - $ref: "#/components/parameters/Form"
        - $ref: "#/components/parameters/OpaqueCursor"
        - name: Limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
      responses:
        "200":
          description: Filing metadata and an optional continuation cursor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CharityFilings"
        "404":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/charity/{ein}/money-network:
    get:
      tags: [Profiles]
      operationId: getCharityMoneyNetwork
      summary: Page through exact counterparties or historical graph evidence.
      parameters:
        - $ref: "#/components/parameters/Ein"
        - name: Scope
          in: query
          schema:
            type: string
            enum: [Latest, Historical]
            default: Latest
        - name: Cursor
          in: query
          description: Opaque graph document cursor returned by NextCursor.
          schema:
            type: string
        - name: Direction
          in: query
          description: Optional direction relative to the requested EIN.
          schema:
            type: string
            enum: [Incoming, Outgoing]
        - $ref: "#/components/parameters/SectionLimit"
      responses:
        "200":
          description: Directed counterparty aggregates with graph evidence.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoneyNetwork"
        "404":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/charity/{ein}/discovery:
    get:
      tags: [Discovery]
      operationId: discoverRelatedOrganizations
      summary: Discover organizations related by cause or region.
      parameters:
        - $ref: "#/components/parameters/Ein"
        - $ref: "#/components/parameters/Form"
        - name: Intent
          in: query
          description: Optional discovery text. The profile cause or mission is used when omitted.
          schema:
            type: string
      responses:
        "200":
          description: Related organizations from the discovery search alias.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DiscoveryResults"
        "404":
          $ref: "#/components/responses/ErrorResponse"
        "503":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/contact:
    post:
      tags: [Forms]
      operationId: submitContactForm
      summary: Submit the site contact form.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactRequest"
      responses:
        "200":
          description: Submission capture status.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubmissionResult"
        "400":
          $ref: "#/components/responses/ErrorResponse"
        "429":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/subscribe:
    post:
      tags: [Forms]
      operationId: subscribeForUpdates
      summary: Subscribe an email address to CharitySense updates.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SubscribeRequest"
      responses:
        "200":
          description: Subscription capture status.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CaptureResult"
        "400":
          $ref: "#/components/responses/ErrorResponse"
        "429":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/charity-question:
    post:
      tags: [Forms]
      operationId: submitCharityQuestion
      summary: Submit a question about one canonical charity profile.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CharityQuestionRequest"
      responses:
        "200":
          description: Question capture status.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QuestionResult"
        "400":
          $ref: "#/components/responses/ErrorResponse"
        "404":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/agent-feedback:
    post:
      tags: [Forms]
      operationId: submitAgentFeedback
      summary: Submit optional integration or data-quality feedback.
      x-openai-isConsequential: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AgentFeedbackRequest"
      responses:
        "200":
          description: Feedback capture status.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FeedbackResult"
        "400":
          $ref: "#/components/responses/ErrorResponse"
        "429":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/assistant/capabilities:
    get:
      tags: [Assistant]
      operationId: getAssistantCapabilities
      summary: Get the assistant's supported and deferred capabilities.
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      responses:
        "200":
          description: Assistant capability lists.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssistantCapabilities"
        "401":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/assistant/chat/stream:
    post:
      tags: [Assistant]
      operationId: streamAssistantChat
      summary: Stream a CharitySense research response as server-sent events.
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      parameters:
        - name: X-CharitySense-Session
          in: header
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AssistantChatRequest"
      responses:
        "200":
          description: SSE frames followed by a data [DONE] frame.
          content:
            text/event-stream:
              schema:
                type: string
        "400":
          $ref: "#/components/responses/ErrorResponse"
        "401":
          $ref: "#/components/responses/ErrorResponse"
        "429":
          $ref: "#/components/responses/ErrorResponse"
  /api/v2/assistant/brochure-extract:
    post:
      tags: [Assistant]
      operationId: extractBrochure
      summary: Extract organization claims from a brochure image.
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BrochureExtractRequest"
      responses:
        "200":
          description: Extracted brochure claims and optional exact EIN resolution.
          content:
            application/json:
              schema:
                type: object
                required: [Extraction]
                properties:
                  Extraction:
                    type: object
                    additionalProperties: true
                  Resolution:
                    type: object
                    additionalProperties: true
                additionalProperties: false
        "400":
          $ref: "#/components/responses/ErrorResponse"
        "401":
          $ref: "#/components/responses/ErrorResponse"
        "422":
          $ref: "#/components/responses/ErrorResponse"
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-CharitySense-API-Key
  parameters:
    Ein:
      name: ein
      in: path
      required: true
      description: Nine-digit Employer Identification Number.
      schema:
        type: integer
        minimum: 10000000
        maximum: 999999999
    Form:
      name: Form
      in: query
      description: Select an available form context. Defaults to the profile's primary form.
      schema:
        type: string
        enum: ["990", 990EZ, 990N, 990PF, 990T]
    Year:
      name: Year
      in: query
      description: Select a filing year. Defaults to the latest filing in the selected form context.
      schema:
        type: integer
    OpaqueCursor:
      name: Cursor
      in: query
      description: Opaque continuation value returned by NextCursor.
      schema:
        type: string
    SectionLimit:
      name: Limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 200
        default: 50
  responses:
    ErrorResponse:
      description: Request error with a stable ErrorCode in detail.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
  schemas:
    Error:
      type: object
      required: [detail]
      properties:
        detail:
          oneOf:
            - type: string
            - type: object
              required: [ErrorCode]
              properties:
                ErrorCode:
                  type: string
                Message:
                  type: string
              additionalProperties: true
      additionalProperties: false
    Health:
      type: object
      required: [Status, Collection, SchemaVersion, Documents]
      properties:
        Status:
          type: string
          const: Healthy
        Collection:
          type: string
          const: data_overlay
        SchemaVersion:
          type: integer
          const: 2
        CompiledAt: {}
        Documents:
          type: integer
      additionalProperties: false
    Stats:
      type: object
      required: [Charities, Filings, ModalLatestYear, ComputedAt]
      properties:
        Charities:
          type: integer
        Filings:
          type: integer
        SectorRevenue:
          type: number
        ProgramDollars:
          type: number
        ModalLatestYear:
          type: integer
        FilingsByForm:
          type: object
          additionalProperties:
            type: integer
        CountsApproximate:
          type: boolean
        SectorOverview:
          $ref: "#/components/schemas/SectorOverview"
        SectorComposition:
          $ref: "#/components/schemas/SectorComposition"
        ComputedAt:
          type: string
          format: date-time
      additionalProperties: false
    TopLists:
      type: object
      required: [Week, Lists]
      properties:
        Week:
          type: integer
        QueryVersions:
          type: array
          items:
            type: string
        Lists:
          type: array
          minItems: 6
          maxItems: 6
          items:
            type: object
            required: [Key, Title, Description, Query, Organizations]
            properties:
              Key:
                type: string
              Title:
                type: string
              Description:
                type: string
              Query:
                type: string
              Organizations:
                type: array
                minItems: 10
                maxItems: 10
                items:
                  type: object
                  required: [EIN, Name]
                  properties:
                    EIN:
                      type: string
                    Name:
                      type: string
                    Location:
                      type: string
                    PrimaryForm:
                      type: string
                  additionalProperties: false
            additionalProperties: false
      additionalProperties: false
    SectorOverview:
      type: object
      required: [Form, OrganizationCount, FilingCount, LatestCompleteYear, Years]
      properties:
        Form:
          type: string
          const: "990"
        OrganizationCount:
          type: integer
        FilingCount:
          type: integer
        LatestCompleteYear:
          type: integer
        Years:
          type: array
          items:
            $ref: "#/components/schemas/SectorYear"
      additionalProperties: false
    SectorYear:
      type: object
      required: [TaxYear, OrganizationCount, FilingCount]
      properties:
        TaxYear:
          type: integer
        OrganizationCount:
          type: integer
        FilingCount:
          type: integer
        Revenue:
          type: object
          properties:
            Total: {type: number}
            Contributions: {type: number}
            ProgramService: {type: number}
            Investment: {type: number}
            Other: {type: number}
          additionalProperties: false
        Expenses:
          type: object
          properties:
            Total: {type: number}
            ProgramServices: {type: number}
            ManagementAndGeneral: {type: number}
            Fundraising: {type: number}
            GrantsTotal: {type: number}
            DomesticOrganizationGrants: {type: number}
            DomesticIndividualGrants: {type: number}
            ForeignGrants: {type: number}
          additionalProperties: false
        BalanceSheet:
          type: object
          properties:
            Assets: {type: number}
            Liabilities: {type: number}
          additionalProperties: false
        Coverage:
          type: object
          additionalProperties:
            type: integer
      additionalProperties: false
    SectorComposition:
      type: object
      required: [RegistryOrganizations, Groups]
      properties:
        RegistryOrganizations:
          type: integer
        RegistryUpdatedAt:
          type: string
          format: date-time
        Groups:
          type: array
          items:
            type: object
            required: [Key, Label, Organizations]
            properties:
              Key:
                type: string
              Label:
                type: string
              Organizations:
                type: integer
            additionalProperties: false
      additionalProperties: false
    CharityPage:
      type: object
      required: [Context, Hero, Verdict, Sections]
      properties:
        Context:
          type: object
          required: [SelectedForm, PrimaryForm, AvailableForms]
          additionalProperties: true
        Hero:
          type: object
          required: [EIN, Name, Form]
          properties:
            EIN:
              type: string
            Name:
              type: string
            Form:
              type: string
            Mission:
              type: string
              description: The selected mission statement for the organization.
            Description:
              type: string
              description: The selected general overview from canonical presentation sources.
            CurrentYearActivity:
              type: string
              description: The primary program accomplishment reported in the selected filing year.
            BrandAssets:
              type: object
              description: Canonical data_web BrandAssets presentation block.
              additionalProperties: true
            Contact:
              type: object
              description: Canonical data_web Contact block, including SocialLinks when captured by enrichment.
              properties:
                SocialLinks:
                  type: array
                  items:
                    type: object
                    additionalProperties: true
              additionalProperties: true
          additionalProperties: true
        Verdict:
          type: object
          additionalProperties: true
        Sections:
          type: array
          items:
            $ref: "#/components/schemas/SectionManifestItem"
        SEO:
          type: object
          description: Published runtime data_seo metadata for this entity.
          additionalProperties: true
        CompiledAt: {}
        SchemaVersion: {}
      additionalProperties: false
    SectionManifestItem:
      type: object
      required: [Id, Kind, Title, Summary, SourceTags, Ref]
      properties:
        Id:
          type: string
        Kind:
          type: string
          enum: [Band, Evidence]
        Title:
          type: string
        Summary:
          type: string
        SourceTags:
          type: array
          items:
            type: string
        Form:
          type: string
        Ref:
          type: string
        Status:
          type: object
          required: [Label, Tone]
          properties:
            Label:
              type: string
            Tone:
              type: string
              enum: [Good, Caution, Concern, Neutral]
          additionalProperties: false
      additionalProperties: true
    CharitySection:
      type: object
      required: [Section, Data, EvidenceRefs]
      properties:
        Section:
          $ref: "#/components/schemas/SectionManifestItem"
        Data:
          description: Canonical section data. MoneyFlow responses conform to MoneyFlowData.
          anyOf:
            - $ref: "#/components/schemas/MoneyFlowData"
            - $ref: "#/components/schemas/RelatedOrganizationsData"
            - type: object
              additionalProperties: true
            - type: array
              items: {}
        EvidenceRefs:
          type: array
          items:
            $ref: "#/components/schemas/EvidenceRef"
        ScheduleIndex:
          type: array
          description: Stable lightweight index for a Schedules response; complete indexed schedules remain in paged Data.
          items:
            $ref: "#/components/schemas/ScheduleIndexItem"
        NextCursor:
          type: string
      additionalProperties: false
    EvidenceRef:
      type: object
      required: [Ref]
      properties:
        Collection:
          type: string
        Form:
          type: string
        TaxYear:
          type: integer
        Ref:
          type: string
        SourcePath:
          type: string
        SourceDocument:
          type: string
        Citation:
          type: string
      additionalProperties: true
    FinancialTrendPoint:
      type: object
      required: [Year]
      properties:
        Year:
          type: integer
        Value:
          type: number
        EvidenceRef:
          type: string
          description: Exact Forms.<Form>.Latest/Filings[n] canonical value reference. Omitted for a year gap.
      additionalProperties: false
    FinancialTrend:
      type: object
      required: [Revenue, Expense, Assets, Liabilities]
      properties:
        Revenue:
          type: array
          items:
            $ref: "#/components/schemas/FinancialTrendPoint"
        Expense:
          type: array
          items:
            $ref: "#/components/schemas/FinancialTrendPoint"
        Assets:
          type: array
          items:
            $ref: "#/components/schemas/FinancialTrendPoint"
        Liabilities:
          type: array
          items:
            $ref: "#/components/schemas/FinancialTrendPoint"
      additionalProperties: false
    MoneyFlowData:
      type: object
      required: [FinancialTrend]
      properties:
        Revenues:
          type: object
          additionalProperties: true
        Expenses:
          type: object
          additionalProperties: true
        Assets:
          type: object
          additionalProperties: true
        Liabilities:
          type: object
          additionalProperties: true
        FundBalance:
          type: object
          additionalProperties: true
        FinancialTrend:
          $ref: "#/components/schemas/FinancialTrend"
      additionalProperties: false
    ScheduleIndexItem:
      type: object
      required: [Name, EvidenceRef]
      properties:
        Name:
          type: string
        EvidenceRef:
          type: string
      additionalProperties: false
    RelationshipItem:
      type: object
      required: [Organization, Roles, RelationshipType, Confidences, Evidence]
      properties:
        Organization:
          type: object
          additionalProperties: true
        Roles:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            enum: [Source, Target]
        RelationshipType:
          type: string
        Confidences:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            enum: [Authoritative, Strong]
        Evidence:
          type: array
          minItems: 1
          items:
            type: object
            additionalProperties: true
      additionalProperties: false
    RelatedOrganizationsData:
      type: object
      required: [Relationships]
      properties:
        Relationships:
          type: array
          items:
            $ref: "#/components/schemas/RelationshipItem"
      additionalProperties: false
    CharityFilings:
      type: object
      required: [Form, Filings]
      properties:
        Form:
          type: string
        Filings:
          type: array
          items:
            type: object
            properties:
              Year:
                type: integer
              TaxPeriodEnd: {}
              Validation: {}
              Source:
                type: object
                additionalProperties: true
            additionalProperties: false
        NextCursor:
          type: string
      additionalProperties: false
    MoneyNetwork:
      type: object
      required: [Scope]
      properties:
        Scope:
          type: string
          enum: [Latest]
        Edges:
          type: array
          items:
            type: object
            additionalProperties: true
        NextCursor:
          type: string
      additionalProperties: false
    SearchHit:
      type: object
      required: [EIN, Name, Match]
      properties:
        EIN: {}
        Name:
          type: string
        Location:
          type: string
        Description:
          type: string
        Cause:
          type: string
        PrimaryForm:
          type: string
        FormTypes:
          type: array
          items:
            type: string
        FamilyID: {}
        OrganizationRole:
          type: string
          enum: [Central, Member, Independent]
        EntityType:
          type: string
        EvidenceTier:
          type: string
          enum: [OfficialWebsite, FiledProgram, FiledMission, ClassificationOnly]
        EvidenceRefs:
          type: array
          items:
            type: string
        WhyMatched:
          type: array
          items:
            type: object
            additionalProperties: true
        Match:
          type: object
          additionalProperties: true
        Explanation:
          type: string
        Similarity:
          type: object
          required: [Score, EvidenceCoverage, Components]
          properties:
            Score:
              type: integer
              minimum: 0
              maximum: 100
            EvidenceCoverage:
              type: integer
              minimum: 0
              maximum: 100
            Components:
              type: array
              items:
                type: object
                required: [Kind, State, Weight]
                properties:
                  Kind:
                    type: string
                  State:
                    type: string
                    enum: [Matched, NotMatched, Unavailable]
                  Score:
                    type: integer
                    minimum: 0
                    maximum: 100
                  Weight:
                    type: number
                  Contribution:
                    type: number
                  Values:
                    type: array
                    items:
                      type: string
                additionalProperties: false
          additionalProperties: false
      additionalProperties: false
    SearchResults:
      type: object
      required: [Query, Mode, Hits, Found, Page]
      properties:
        Query:
          type: string
        Mode:
          type: string
          enum: [Identity, Discovery]
        Hits:
          type: array
          items:
            $ref: "#/components/schemas/SearchHit"
        Found:
          type: integer
        Page:
          type: integer
        QueryVersion:
          type: string
        NextCursor:
          type: string
        Resolution:
          type: object
          additionalProperties: true
      additionalProperties: false
    DiscoveryResults:
      type: object
      required: [Intent, PolicyVersion, Weights, Organizations]
      properties:
        Intent: {}
        PolicyVersion:
          type: string
        Weights:
          type: object
          additionalProperties:
            type: number
        Organizations:
          type: array
          items:
            $ref: "#/components/schemas/SearchHit"
      additionalProperties: false
    ContactRequest:
      type: object
      required: [Name, Email, Subject, Message]
      properties:
        Name:
          type: string
          maxLength: 120
        Email:
          type: string
          format: email
        Subject:
          type: string
          maxLength: 200
        Message:
          type: string
          maxLength: 8000
        Interest:
          type: string
        EIN:
          type: string
        NTEE:
          type: string
        Surface:
          type: string
        SourceChannel:
          type: string
      additionalProperties: false
    SubscribeRequest:
      type: object
      required: [Email]
      properties:
        Email:
          type: string
          format: email
        Source:
          type: string
      additionalProperties: false
    CharityQuestionRequest:
      type: object
      required: [EIN, Question, Email]
      properties:
        EIN:
          oneOf:
            - type: integer
            - type: string
        Question:
          type: string
          maxLength: 4000
        Email:
          type: string
          format: email
      additionalProperties: false
    AgentFeedbackRequest:
      type: object
      required: [Message]
      properties:
        FeedbackType:
          type: string
        Message:
          type: string
          maxLength: 4000
        EIN:
          type: string
        Metadata:
          type: object
          additionalProperties: true
      additionalProperties: false
    CaptureResult:
      type: object
      required: [Stored, Notified]
      properties:
        Stored:
          type: boolean
        Notified:
          type: boolean
      additionalProperties: false
    SubmissionResult:
      type: object
      required: [SubmissionID, Stored, Notified]
      properties:
        SubmissionID:
          type: string
        Stored:
          type: boolean
        Notified:
          type: boolean
      additionalProperties: false
    QuestionResult:
      type: object
      required: [RequestID, Stored, Notified]
      properties:
        RequestID:
          type: string
        Stored:
          type: boolean
        Notified:
          type: boolean
      additionalProperties: false
    FeedbackResult:
      type: object
      required: [FeedbackID, Stored]
      properties:
        FeedbackID:
          type: string
        Stored:
          type: boolean
      additionalProperties: false
    AssistantCapabilities:
      type: object
      required: [Supported, NotYet]
      properties:
        Supported:
          type: array
          items:
            type: string
        NotYet:
          type: array
          items:
            type: string
      additionalProperties: false
    AssistantChatRequest:
      type: object
      required: [Message]
      properties:
        Message:
          type: string
          minLength: 1
          maxLength: 2000
        History:
          type: array
          maxItems: 20
          items:
            type: object
            required: [Role, Content]
            properties:
              Role:
                type: string
                enum: [user, assistant]
              Content:
                type: string
                maxLength: 2000
            additionalProperties: false
        Context:
          type: object
          properties:
            Path:
              type: string
            EIN:
              type: string
            CharityName:
              type: string
            SearchQuery:
              type: string
          additionalProperties: false
      additionalProperties: false
    BrochureExtractRequest:
      type: object
      required: [Image]
      properties:
        Image:
          type: string
          description: Base64 data URL for a supported brochure image.
        Context:
          type: object
          properties:
            Path:
              type: string
          additionalProperties: false
      additionalProperties: false
