> ## Documentation Index
> Fetch the complete documentation index at: https://docs.truscan.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Answer a question with citations



## OpenAPI

````yaml /api-reference/answer.json post /api/answer
openapi: 3.1.0
info:
  title: Truscan Answer
  version: 1.0.0
  description: >-
    Cited answers assembled from pages the search service ranked and read.


    Nothing here is generated. Every sentence in `answer` is quoted verbatim
    from the source its marker points at, which is what makes a citation
    verifiable rather than plausible: the quoted span and the marker are the
    same object.


    One answer is one charge. The search behind it and the pages it reads are
    included in that price, so the same question at a deeper tier reads further
    and costs the same.
servers:
  - url: https://api.truscan.co
security:
  - bearerAuth: []
paths:
  /api/answer:
    post:
      summary: Answer a question with citations
      operationId: answer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AnswerRequest'
      responses:
        '200':
          description: The assembled answer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AnswerEnvelope'
              example:
                success: true
                message: Answered from 2 sources.
                result:
                  id: ans_8d3ddecc038c10d9
                  query: >-
                    why is TLS certificate pinning discouraged in mobile apps
                    now
                  answer: >-
                    Originally, certificate pinning was designed to prevent
                    monster-in-the-middle (MITM) attacks by associating a
                    hostname with a specific TLS certificate. [2]


                    The cost-benefit equation has changed: the risk of a rogue
                    certificate is now quite low, whereas the risk of your own
                    app breaking due to pinning is comparatively higher. [1]
                  passages:
                    - text: >-
                        Originally, certificate pinning was designed to prevent
                        monster-in-the-middle (MITM) attacks by associating a
                        hostname with a specific TLS certificate.
                      source: 2
                      score: 0.7412
                    - text: >-
                        The cost-benefit equation has changed: the risk of a
                        rogue certificate is now quite low, whereas the risk of
                        your own app breaking due to pinning is comparatively
                        higher.
                      source: 1
                      score: 0.6903
                  sources:
                    - 'n': 1
                      url: >-
                        https://blog.cloudflare.com/why-certificate-pinning-is-outdated/
                      title: >-
                        Avoiding downtime: modern alternatives to outdated
                        certificate pinning practices
                      domain: blog.cloudflare.com
                      score: 0.614
                    - 'n': 2
                      url: >-
                        https://www.sans.org/blog/tls-ssl-failures-and-some-thoughts-on-cert-pinning-part-1
                      title: TLS/SSL failures and some thoughts on cert pinning
                      domain: sans.org
                      author: Jake Williams
                      score: 0.552
                  format: json
                  usage:
                    answers: 1
                    search_requests: 1
                    pages_read: 9
                  stats:
                    took_ms: 13095
                    search_ms: 12940
                    sources_read: 9
                    considered: 25
                    cached: false
        '401':
          $ref: '#/components/responses/Failure'
        '402':
          $ref: '#/components/responses/Failure'
        '422':
          $ref: '#/components/responses/Failure'
        '429':
          $ref: '#/components/responses/Failure'
        '502':
          $ref: '#/components/responses/Failure'
components:
  schemas:
    AnswerRequest:
      type: object
      required:
        - query
      properties:
        query:
          type: string
          maxLength: 512
          description: The question. `q` is accepted as an alias.
        tier:
          type: string
          enum:
            - instant
            - deep
            - deep_reasoning
          default: instant
          description: >-
            Search depth behind the answer. Instant reads up to 10 pages, deep
            50, deep reasoning 100, so a deeper tier has more to quote from.
        sources:
          type: integer
          minimum: 1
          maximum: 50
          default: 10
          description: How many ranked results the answer may quote from.
        passages:
          type: integer
          minimum: 1
          maximum: 12
          default: 5
          description: >-
            How many quotes the answer carries. Past a dozen it stops reading as
            an answer and starts reading as the search results again.
        format:
          type: string
          enum:
            - json
            - markdown
            - text
          default: json
        site:
          type: string
          description: Restrict to one domain.
        lang:
          type: string
        freshness:
          type: string
          enum:
            - any
            - day
            - week
            - month
            - year
        category:
          type: string
          enum:
            - general
            - news
            - science
            - images
            - videos
            - it
    AnswerEnvelope:
      type: object
      properties:
        success:
          type: boolean
          const: true
        message:
          type: string
        result:
          $ref: '#/components/schemas/AnswerResponse'
    AnswerResponse:
      type: object
      properties:
        id:
          type: string
          examples:
            - ans_8d3ddecc038c10d9
        query:
          type: string
        corrected_query:
          type: string
          description: >-
            Present only when the original question matched nothing and the
            search behind this answer ran a spelling correction instead.
        answer:
          type: string
          description: >-
            The assembled prose, with [n] markers pointing into sources. Every
            marker resolves: a source nothing quoted is dropped from the list
            and the numbering is contiguous from 1.


            Empty when nothing quotable was found, which is deliberate. An
            answer with no support is the one thing this endpoint will not
            return.
        passages:
          type: array
          items:
            $ref: '#/components/schemas/Passage'
        sources:
          type: array
          items:
            $ref: '#/components/schemas/Source'
          description: >-
            Only the documents actually quoted. This is a citation list, not the
            search results.
        rendered:
          type: string
          description: >-
            The markdown or text view, with the sources as a numbered list
            underneath. Empty for format=json.
        format:
          type: string
          enum:
            - json
            - markdown
            - text
        usage:
          $ref: '#/components/schemas/Usage'
        stats:
          $ref: '#/components/schemas/Stats'
    Failure:
      type: object
      properties:
        success:
          type: boolean
          const: false
        message:
          type: string
        result:
          type: object
          properties:
            code:
              type: string
    Passage:
      type: object
      description: One quoted span and where it came from.
      properties:
        text:
          type: string
          description: Quoted verbatim from the source. Nothing is rewritten.
        source:
          type: integer
          description: One-based index into sources, matching the [n] marker in answer.
        score:
          type: number
          description: >-
            The passage's own match against the question, weighted by how well
            search ranked the page it came from.
    Source:
      type: object
      properties:
        'n':
          type: integer
          description: The citation number used in answer.
        url:
          type: string
          format: uri
        title:
          type: string
        domain:
          type: string
        author:
          type: string
          description: >-
            Present when the page declared one. Read from the page itself, not
            inferred.
        published_at:
          type: string
          format: date-time
        score:
          type: number
          description: >-
            The search rank score, carried through so citation order can be
            checked against the ranking /api/search would have returned.
    Usage:
      type: object
      description: >-
        What this call consumed.


        Only answers is billed. The rate is all-inclusive, so search_requests
        and pages_read report the work that price covered rather than separate
        charges: they are here so you can see what a question actually took, and
        tune the tier against it.


        Units rather than dollars: the rate card belongs to the billing service,
        and restating prices here is how two numbers drift apart. Multiply
        answers by /api/billing/pricing, which is generated from the same
        constants that charge the request.
      properties:
        answers:
          type: integer
          description: The billed line. One per call.
        search_requests:
          type: integer
          description: >-
            Covered by the answer price, not charged. Zero when the search
            behind the answer was served from cache.
        pages_read:
          type: integer
          description: >-
            Pages search delivered with a body, covered by the answer price. A
            page that failed to fetch is not counted.
    Stats:
      type: object
      properties:
        took_ms:
          type: integer
        search_ms:
          type: integer
          description: >-
            Time spent in search, including the pages it read. Assembly is the
            remainder and is measured in milliseconds.
        sources_read:
          type: integer
          description: >-
            How many results carried page content. A result without a body can
            still be cited from its engine snippet, scored below any real
            passage.
        considered:
          type: integer
          description: How many passages were available before selection.
        cached:
          type: boolean
          description: >-
            Whether the search behind this answer was served from cache. The
            answer itself is not cached.
  responses:
    Failure:
      description: >-
        The envelope with success false. result carries the machine-readable
        code and nothing else; the HTTP status line carries the real status.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Failure'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key, sent as `Authorization: Bearer enc_…`. A dashboard session
        cookie works on the same route.

````