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

# Rate Quote (Read-Only)

> Rates the quote a create-quote request WOULD create, and returns the rating
results — **without persisting anything**. No quote is stored, no rating run
is recorded, and no existing entity is touched. Use it to preview premium
for a prospective quote, or to rate a quote you manage in your own system.

**This endpoint is a read, not a mutation** — as is its by-id sibling
`POST /api/v1/companies/{companyId}/quotes/{quoteId}/rate`, which rates a
saved quote without modifying it. The results exist only in the response, so
**if you want them stored, write them back yourself** with
`PATCH /api/v1/companies/{companyId}/entities/quote/{entityId}` — see the
Rating overview's *Persisting rating results*. Copy the returned
`fullTermPricingInfo` (including `pricingComponents` and computed totals)
when it is present, read the quote back to verify the committed values, and
only then bind it. Bind reads the persisted quote, not this rate response.

The request body carries the exact create-quote payload under `data` (the
same flat field bag you would `POST` to
`/api/v1/companies/{companyId}/entities/quote`), plus the
`ratingWorkflowName` naming which configured rating workflow to run.

**Semantics — "rate the quote this body would create."** The `data` bag is
validated with the identical create-quote pipeline (shape, resolution,
tenant invariants, entity invariants) with the same rules an external
create applies: embedded exposures must reference existing Exposure records
by `id` (id-less / draft embedded values are rejected). A body that
create-quote would reject fails here with the identical structured `400`.
Then the named rating workflow runs over the resolved quote.

Hosted rating supports `newBusiness`, `renewal`, and `endorsement` quote
types. `cancellation` and `reinstatement` return a structured
`400 InvalidRequest` before any rater or vendor call because those
transactions preserve the source policy rating result and derive or restore
pricing instead of repricing.

**Exposure id references are looked up and merged.** Because an API-key
caller references exposures by `id` (embedded exposures cannot be
inline-created over the API), each referenced Exposure's stored fields are
fetched and merged under the reference before rating, so the exposure is
rated against its real stored data rather than a blank record. Fields you
**supply inline win** over the stored values, per top-level field (the body
is treated as a draft-edit over the stored exposure). This lookup is
read-only — nothing is persisted. (Note: this is an interim behavior for
`EmbeddedExposure` exposure references; join-linked entities are not
hydrated.)

The `200` response echoes the same bag back under `data`, enriched with the
rating outputs (e.g. `exposureRatingResponse` on each exposure and the
full-term policy rating containers).

**The response reflects only this run.** The rating workflow clears the
containers it owns before any rater runs and rebuilds them from this run's
output, so rating containers your request body happens to carry from an
earlier run are **not** echoed back, and a rate that prices nothing returns
those containers empty rather than repeating what you sent.

**Rating failures also return `200`** — with a `diagnostics` array
describing what went wrong and **no `data`**. Check for the presence of
`data` to detect success, not the HTTP status. Invalid requests (anything
under the `400`/`404`/`422` descriptions below) are still rejected with
their status codes; only failures during rating execution itself (e.g. a
rating vendor error) report as `200` + `diagnostics`.

**Required permission:** `quote.rate`




## OpenAPI

````yaml /openapi/generated-external-api.yaml post /api/v1/companies/{companyId}/quotes/rate
openapi: 3.0.3
info:
  title: AI Insurance External API
  description: External API for AI Insurance platform
  version: 1.0.0
  contact:
    email: support@aiinsurance.io
servers:
  - url: https://go.aiinsurance.io
    description: Production
security:
  - ApiKeyAuth: []
paths:
  /api/v1/companies/{companyId}/quotes/rate:
    post:
      tags:
        - Field Model Rating
      summary: Rate Quote (Read-Only)
      description: >
        Rates the quote a create-quote request WOULD create, and returns the
        rating

        results — **without persisting anything**. No quote is stored, no rating
        run

        is recorded, and no existing entity is touched. Use it to preview
        premium

        for a prospective quote, or to rate a quote you manage in your own
        system.


        **This endpoint is a read, not a mutation** — as is its by-id sibling

        `POST /api/v1/companies/{companyId}/quotes/{quoteId}/rate`, which rates
        a

        saved quote without modifying it. The results exist only in the
        response, so

        **if you want them stored, write them back yourself** with

        `PATCH /api/v1/companies/{companyId}/entities/quote/{entityId}` — see
        the

        Rating overview's *Persisting rating results*. Copy the returned

        `fullTermPricingInfo` (including `pricingComponents` and computed
        totals)

        when it is present, read the quote back to verify the committed values,
        and

        only then bind it. Bind reads the persisted quote, not this rate
        response.


        The request body carries the exact create-quote payload under `data`
        (the

        same flat field bag you would `POST` to

        `/api/v1/companies/{companyId}/entities/quote`), plus the

        `ratingWorkflowName` naming which configured rating workflow to run.


        **Semantics — "rate the quote this body would create."** The `data` bag
        is

        validated with the identical create-quote pipeline (shape, resolution,

        tenant invariants, entity invariants) with the same rules an external

        create applies: embedded exposures must reference existing Exposure
        records

        by `id` (id-less / draft embedded values are rejected). A body that

        create-quote would reject fails here with the identical structured
        `400`.

        Then the named rating workflow runs over the resolved quote.


        Hosted rating supports `newBusiness`, `renewal`, and `endorsement` quote

        types. `cancellation` and `reinstatement` return a structured

        `400 InvalidRequest` before any rater or vendor call because those

        transactions preserve the source policy rating result and derive or
        restore

        pricing instead of repricing.


        **Exposure id references are looked up and merged.** Because an API-key

        caller references exposures by `id` (embedded exposures cannot be

        inline-created over the API), each referenced Exposure's stored fields
        are

        fetched and merged under the reference before rating, so the exposure is

        rated against its real stored data rather than a blank record. Fields
        you

        **supply inline win** over the stored values, per top-level field (the
        body

        is treated as a draft-edit over the stored exposure). This lookup is

        read-only — nothing is persisted. (Note: this is an interim behavior for

        `EmbeddedExposure` exposure references; join-linked entities are not

        hydrated.)


        The `200` response echoes the same bag back under `data`, enriched with
        the

        rating outputs (e.g. `exposureRatingResponse` on each exposure and the

        full-term policy rating containers).


        **The response reflects only this run.** The rating workflow clears the

        containers it owns before any rater runs and rebuilds them from this
        run's

        output, so rating containers your request body happens to carry from an

        earlier run are **not** echoed back, and a rate that prices nothing
        returns

        those containers empty rather than repeating what you sent.


        **Rating failures also return `200`** — with a `diagnostics` array

        describing what went wrong and **no `data`**. Check for the presence of

        `data` to detect success, not the HTTP status. Invalid requests
        (anything

        under the `400`/`404`/`422` descriptions below) are still rejected with

        their status codes; only failures during rating execution itself (e.g. a

        rating vendor error) report as `200` + `diagnostics`.


        **Required permission:** `quote.rate`
      operationId: rateQuote
      parameters:
        - $ref: '#/components/parameters/companyId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - data
              properties:
                ratingWorkflowName:
                  type: string
                  description: >
                    The configured rating workflow to run. **Required in
                    practice** —

                    there is no default even when a single workflow is
                    configured —

                    but it is not schema-required: rather than a shape
                    rejection, a

                    missing or unknown name returns a `400` listing the
                    configured

                    workflow names (and a company with no workflows configured

                    returns a `422`), so callers get an actionable error naming
                    the

                    valid options.
                  example: standard
                data:
                  type: object
                  description: >
                    The create-quote payload — the flat field bag, unchanged.

                    Custom fields are validated against your company's field

                    configuration (unknown fields rejected, required fields

                    enforced, values matched to their configured types).
                    Embedded

                    exposure values are validated per-field against the Exposure

                    configuration and must reference existing Exposure records
                    by

                    `id`; each referenced exposure's stored fields are then
                    merged

                    in for rating, with any fields you supply inline winning
                    over

                    the stored values.
                  additionalProperties: true
            examples:
              newBusinessQuote:
                summary: Rate a new-business quote with embedded exposures
                value:
                  ratingWorkflowName: standard
                  data:
                    quoteType: newBusiness
                    primaryInsured:
                      id: 550e8400-e29b-41d4-a716-446655440001
                      exposureName: Acme Co
                    otherExposures:
                      - id: 550e8400-e29b-41d4-a716-446655440002
                        exposureName: Beta LLC
      responses:
        '200':
          description: >
            The rating outcome. Nothing is persisted either way.


            **Success:** `data` carries the quote bag enriched with rating
            outputs.


            **Rating failure:** the response is still `200`, with `diagnostics`

            describing what went wrong and **no `data`** — the absent `data` is

            the failure signal, so do not treat the presence of `diagnostics`

            alone as failure: `severity: warning` diagnostics ride alongside a

            successful `data` when a rater reports them. Rating failures are

            engine/vendor faults during rating execution; an invalid *request*
            is

            still a `4xx`, and an unexpected application fault is still a `500`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    description: |
                      The same field bag from the request, enriched with rating
                      outputs (per-exposure `exposureRatingResponse`, and the
                      full-term policy rating containers). Absent when the rate
                      failed.
                    additionalProperties: true
                  diagnostics:
                    type: array
                    description: >
                      Rating diagnostics. Present with `severity: error` entries

                      when the rate failed (in which case `data` is absent), or

                      with `severity: warning` entries beside a successful
                      `data`.
                    items:
                      $ref: '#/components/schemas/RatingDiagnostic'
              examples:
                ratedQuote:
                  summary: Rated new-business quote
                  value:
                    data:
                      quoteType: newBusiness
                      primaryInsured:
                        id: 550e8400-e29b-41d4-a716-446655440001
                        exposureName: Acme Co
                        exposureRatingResponse:
                          premium: 1000
                      otherExposures:
                        - id: 550e8400-e29b-41d4-a716-446655440002
                          exposureName: Beta LLC
                          exposureRatingResponse:
                            premium: 1000
                      fullTermPolicyRatingResult:
                        policyPremium: 3000
                        policyGrandTotal: 3500
                ratedWithWarnings:
                  summary: Rated quote with warning diagnostics riding beside it
                  value:
                    data:
                      quoteType: newBusiness
                      primaryInsured:
                        id: 550e8400-e29b-41d4-a716-446655440001
                        exposureName: Acme Co
                        exposureRatingResponse:
                          premium: 1000
                      fullTermPolicyRatingResult:
                        policyPremium: 3000
                        policyGrandTotal: 3500
                    diagnostics:
                      - severity: warning
                        code: rating-output-incomplete
                        message: Premium is provisional
                        location:
                          stageIndex: 0
                          raterDebugName: exposure-rater-1
                          targetPath: quote.primaryInsured
                          segmentWindows:
                            - startDate: '2026-01-01T00:00:00.000Z'
                              endDate: '2027-01-01T00:00:00.000Z'
                ratedWithConfiguredWarning:
                  summary: Rated quote carrying a configured rating warning
                  description: >
                    A warning the company authored on the rating workflow

                    (`ratingWorkflows[].warnings`). It has no `location` — the

                    configuration raised it, not a stage — and the rate
                    succeeded,

                    so `data` is present.
                  value:
                    data:
                      quoteType: newBusiness
                      policyStartDate: '2026-07-01'
                      policyEndDate: '2026-07-08'
                      fullTermPolicyRatingResult:
                        policyPremium: 3000
                        policyGrandTotal: 3500
                    diagnostics:
                      - severity: warning
                        code: rating-workflow-warning
                        message: >-
                          The accident classification "Camp - Day 5 Days or
                          Less" requires a policy term of 5 days or less.
                erroredRate:
                  summary: Rating failed — diagnostics returned, no data
                  value:
                    diagnostics:
                      - severity: error
                        code: inscipher-tax-calculation-failed
                        message: >-
                          An error occurred - please contact support, the
                          technical details are: InsCipher tax calculation
                          failed for exposure: server_error
        '400':
          description: >
            The `data` bag failed create-quote validation, `ratingWorkflowName`

            is missing or names no configured workflow, or a rating target the

            selected workflow requires (e.g. exposures) is empty or missing on
            the

            quote, or the workflow's configured preconditions are unmet, or

            `quoteType` is `cancellation` or `reinstatement`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                invalidData:
                  summary: >-
                    Body create-quote would reject (embedded exposure missing
                    id)
                  value:
                    error:
                      code: InvalidEmbeddedExposureReference
                      message: embedded Exposure at 'primaryInsured' is missing an 'id'
                unsupportedQuoteType:
                  summary: The quote type preserves rating instead of repricing
                  value:
                    error:
                      code: InvalidRequest
                      message: >-
                        Cancellation quotes cannot be rated: cancellation
                        preserves the source policy rating result and derives
                        pricing from earned amounts
                targetMissing:
                  summary: A rating target the workflow requires is empty or missing
                  value:
                    error:
                      code: rating-workflow-target-missing
                      message: >-
                        Rating workflow "standard" targets "quote.exposures",
                        which is empty or missing on the quote after hydration
                preconditionsUnmet:
                  summary: The workflow's configured preconditions are unmet
                  value:
                    error:
                      code: rating-workflow-preconditions-unmet
                      message: >-
                        Rating workflow "standard" has 1 unmet precondition(s):
                        Add at least one exposure before rating
                unknownWorkflow:
                  summary: Unknown rating workflow name
                  value:
                    error:
                      code: unknown-rating-workflow-name
                      message: >-
                        No rating workflow named "premium" is configured;
                        available: standard
                missingWorkflow:
                  summary: No ratingWorkflowName supplied
                  value:
                    error:
                      code: no-rating-workflow-name-supplied
                      message: >-
                        No rating workflow name was supplied; pass
                        ratingWorkflowName on the rate request as one of:
                        standard
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          description: The company has no rating workflows configured.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                noWorkflows:
                  summary: No rating workflows configured
                  value:
                    error:
                      code: no-rating-workflows-configured
                      message: >-
                        No rating workflows are configured for this company;
                        rating requires a configured rating workflow
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  parameters:
    companyId:
      name: companyId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Company identifier
  schemas:
    RatingDiagnostic:
      type: object
      description: >
        A rating diagnostic — the rate ran and this is what it has to report.

        `severity: error` entries explain why a rate failed (a failed rate
        returns

        HTTP `200` with `diagnostics` and **no `data`** — the missing `data` is
        the

        failure signal). `severity: warning` entries ride alongside a successful

        `data`, so the presence of diagnostics alone does not mean the rate
        failed.
      required:
        - severity
        - code
        - message
      properties:
        severity:
          type: string
          enum:
            - error
            - warning
          description: >
            `error` — the rate failed and no rated quote is returned. `warning`
            —

            informational; it does not by itself fail the rate. Warnings usually

            ride beside a successful `data`, but warnings emitted before a
            failing

            step also appear on a failed rate's diagnostics — always check for
            the

            presence of `data`, never for warning entries, to detect success.
        code:
          type: string
          description: |
            Stable, machine-readable failure code, safe to branch on (e.g.
            `inscipher-tax-calculation-failed`, `rating-service-error`).
          example: inscipher-tax-calculation-failed
        message:
          type: string
          description: Human-readable description of what went wrong.
          example: Rating failed - please contact support.
        location:
          type: object
          description: >
            Where in the rating workflow the diagnostic arose. Present when a
            rater

            reported the diagnostic mid-run (the engine stamps the stage,
            target,

            and rated window(s)) — including most rating-vendor failures, which
            the

            failing stage's rater now reports itself; absent for failures
            classified

            outside any one stage (e.g. a rating-service transport failure).
          required:
            - stageIndex
            - raterDebugName
            - segmentWindows
          properties:
            stageIndex:
              type: integer
              minimum: 0
              description: 0-based index into the rating workflow's stages.
            raterDebugName:
              type: string
              description: The configured debug name of the stage's rater.
              example: exposure-rater-1
            targetPath:
              type: string
              description: |
                The rated target that produced the diagnostic; absent for a
                stage-level failure with no single target.
              example: quote.exposures[0]
            segmentWindows:
              type: array
              description: >
                The rated window(s) the diagnostic applies to, as ISO-8601

                date-time instants. One entry for a per-segment stage; a
                full-term

                stage lists every window its target covers.
              items:
                type: object
                required:
                  - startDate
                  - endDate
                properties:
                  startDate:
                    type: string
                    format: date-time
                  endDate:
                    type: string
                    format: date-time
    ErrorResponse:
      type: object
      description: Standard error response for all external API endpoints
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Machine-readable error code
              example: VALIDATION_ERROR
            message:
              type: string
              description: Human-readable error message
              example: 'submissionId: Required field is missing'
            userMessages:
              type: array
              description: >-
                Clean, verbatim-displayable messages — one entry per failure,
                free of error-code tags, field paths, and internal noise.
                Suitable for showing to end users as-is.
              items:
                type: string
              example:
                - Exposures of type 'company' require an address
            details:
              type: array
              description: Additional details for validation errors (field-level errors)
              items:
                type: object
                properties:
                  field:
                    type: string
                    description: The field that caused the error
                    example: submissionId
                  code:
                    type: string
                    description: Stable problem code for this individual validation failure
                    example: BLANK_LIST_ELEMENT
                  reason:
                    type: string
                    description: Stable reason the value violates its canonical contract
                    example: blank-list-element
                  expected:
                    type: string
                    description: The expected canonical value contract
                    example: nonblank trimmed string
                  message:
                    type: string
                    description: Description of the field error
                    example: Required field is missing
  responses:
    Unauthorized:
      description: Unauthorized - Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missingApiKey:
              summary: Missing API key
              value:
                error:
                  code: AuthenticationError
                  message: API key authentication required
                  userMessages:
                    - API key authentication required
            invalidApiKey:
              summary: >-
                Invalid API key (e.g. unknown key, or a Bearer token used
                instead of an API key)
              value:
                error:
                  code: AuthenticationError
                  message: Invalid API key
                  userMessages:
                    - Invalid API key
    Forbidden:
      description: Forbidden - Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            insufficientPermissions:
              summary: Insufficient permissions
              value:
                error:
                  code: AuthorizationError
                  message: User is not authorized to perform the requested action
                  userMessages:
                    - User is not authorized to perform the requested action
            companyMismatch:
              summary: A valid API key naming another company in the URL
              value:
                error:
                  code: AuthorizationError
                  message: API key is not scoped to the requested company
                  userMessages:
                    - API key is not scoped to the requested company
    InternalServerError:
      description: Internal Server Error - Unexpected error occurred
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            internalError:
              summary: Unexpected server error
              value:
                error:
                  code: UncaughtActionError
                  message: Uncaught error occurred in <actionName>
                  userMessages:
                    - An unexpected error occurred. Please try again later.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        API key authentication. Send your raw API key as the `Authorization`
        header value with NO scheme prefix — `Authorization: YOUR-API-KEY`. Do
        NOT prefix it with `Bearer ` or `ApiKey `, and do not use an `X-API-Key`
        header; those are not accepted.

````