> ## 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.

# Generate Quote from Policy (Stateless)

> Returns the editable Quote data a transaction on an existing policy would
start from — **without persisting anything**. No quote is stored, no quote
number or id is allocated, no relationship is created, no audit row is
written, and no token, draft session or retry receipt is minted. Generation
is a pure read.

Use it to build your own transaction UI: generate, let your user edit the
returned `data`, then either bind it by value with
[Bind Quote by Reference or by Value](/api-reference/field-model-policy-transactions/bind-quote-by-reference-or-by-value),
or save it as a quote and bind that quote, as described below. Bound by
value, everything the server needs travels in the request, so there is no
state to keep between the two calls.

**Changing a bound policy through a saved quote.** An endorsement,
cancellation or reinstatement can go through a quote of its own, as in the
app, so that its bind replaces the policy's invoices the way the quote's
invoicing says ([Quote invoicing](/api-reference/invoicing/quote-invoicing#starting-a-change-to-a-bound-policy)):

1. Generate the change's draft here. Nothing is saved.
2. Save it with [Create Entity](/api-reference/entities/create-entity)
   (`POST …/entities/quote`): send the draft's whole `data` with your
   edits applied (for an endorsement, change only the fields that change
   and keep the rest as generated), and set two fields the draft leaves
   `null` unless your Conversion Rules write them: `referencingPolicy`, the
   policy's id, and the change's date in `endorsementEffectiveDate`,
   `cancellationEffectiveDate` or `reinstatementDate`. Use the
   `effectiveDate` you generated with, written the way the quote writes
   `policyStartDate`, for example
   `{"date": "2026-12-15", "timezone": "America/New_York"}`. An endorsement
   generated with an `endDate` also sets `endorsementEndDate`; without it
   the endorsement runs to `policyEndDate`.
3. For an endorsement, rate the quote with
   [Rate Saved Quote by Id](/api-reference/field-model-rating/rate-saved-quote-by-id),
   which returns the rating without saving it on the quote (a rating that
   fails is still a `200`, with `diagnostics` and no `data`), and save the
   rating outputs from its `data` with
   [Update Entity](/api-reference/entities/update-entity). Don't rate a
   cancellation or reinstatement (it returns `400`): its draft already has
   the pricing the platform derives.
4. Bind it with [Bind Quote](/api-reference/field-model-policy-transactions/bind-quote)
   and `{"invoices": "generate"}`, or prepare its plan with the
   [quote invoicing](/api-reference/invoicing/quote-invoicing) endpoints and
   bind with `{"invoices": "saved"}`.

Saving a change quote without `referencingPolicy` is refused. Without its
change date it saves, but
[Generate Quote Invoices](/api-reference/policy-invoicing/generate-quote-invoices)
and [Attach Quote Invoice Plan](/api-reference/policy-invoicing/attach-quote-invoice-plan)
refuse it with `400 finv2-invalid-quote-transaction-metadata`, and its bind
returns `400`.
`validationIssues` reports neither field, because a bind by value takes
the policy and the date from its own request.

**What produces the data.** Your company's configured Conversion Rules for
(`POLICY_TO_QUOTE`, the requested `transactionType`) are evaluated
server-side against a single resolved segment of the source policy. Each rule
writes one destination field on the Quote. The rules are part of your
field-model configuration — what carries between a policy and a quote is
authored and reviewable, not inferred.

**The data is the finished draft.** It has every field your Quote
configuration declares, with every calculated field worked out as a save
would, `fullTermBillingInfo` included (null while policy invoicing is
disabled). A field nothing fills is `null`. A value that needs a saved quote,
such as a generated quote number, is `null` until the quote is saved.
Nothing is saved. `quoteType` is set from `transactionType` — `ENDORSE`
gives `endorsement`, `RENEW` gives `renewal`, `CANCEL` gives
`cancellation` and `REINSTATE` gives `reinstatement` — whatever your rules
write, so calculated fields that read it are worked out for that
transaction. A field you must supply that the draft lacks is reported in
`validationIssues` and comes back `null`. If a value fails its field's type
check, the calculated fields are not worked out and the finding names the
field.

**Which segment of the policy is read**, per transaction type — always
against the policy's latest committed version:

| `transactionType` | Segment read |
| --- | --- |
| `ENDORSE` | the segment covering `effectiveDate` |
| `CANCEL` | the segment covering `effectiveDate` |
| `REINSTATE` | the segment covering `effectiveDate` on the cancelled version |
| `RENEW` | the last segment of the expiring term |

**Four transaction types, and why `NEW_BUSINESS` is not one of them.** This
operation converts *from* a policy, and new business has no source policy to
convert from. New business is fully supported at bind: compose the field bag
yourself and post it, exactly as you do today.

**Concurrency.** `sourcePolicy.policyVersion` is the version the returned bag
was derived from. Echo it as `expectedPolicyVersion` on the bind request and
the bind is refused with a `409` if the policy moved while your user was
editing. That is the entire concurrency contract — the server holds nothing
on your behalf.

**`200` with findings vs. an error.** The dividing rule is FIXABILITY, not
severity. Anything your user can fix by editing the returned draft comes back
as a `200` with entries in `validationIssues` and a usable `data` bag.
Anything they cannot fix by editing — an unknown policy, a policy in the
wrong state for the transaction, missing or failing Conversion Rules — is a
structured error with no draft at all.

Conversion uses the company’s explicitly authored rules. Missing required
configuration is an error; matching field names do not supply a fallback.

**Required permission:** the requested `transactionType`'s own permission —
`policy.endorse`, `policy.cancel`, `policy.reinstate` or `policy.renew`.
Generating is the read half of authoring that transaction.




## OpenAPI

````yaml /openapi/generated-external-api.yaml post /api/v1/companies/{companyId}/quotes/generate
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/generate:
    post:
      tags:
        - Field Model Policies
      summary: Generate Quote from Policy (Stateless)
      description: >
        Returns the editable Quote data a transaction on an existing policy
        would

        start from — **without persisting anything**. No quote is stored, no
        quote

        number or id is allocated, no relationship is created, no audit row is

        written, and no token, draft session or retry receipt is minted.
        Generation

        is a pure read.


        Use it to build your own transaction UI: generate, let your user edit
        the

        returned `data`, then either bind it by value with

        [Bind Quote by Reference or by
        Value](/api-reference/field-model-policy-transactions/bind-quote-by-reference-or-by-value),

        or save it as a quote and bind that quote, as described below. Bound by

        value, everything the server needs travels in the request, so there is
        no

        state to keep between the two calls.


        **Changing a bound policy through a saved quote.** An endorsement,

        cancellation or reinstatement can go through a quote of its own, as in
        the

        app, so that its bind replaces the policy's invoices the way the quote's

        invoicing says ([Quote
        invoicing](/api-reference/invoicing/quote-invoicing#starting-a-change-to-a-bound-policy)):


        1. Generate the change's draft here. Nothing is saved.

        2. Save it with [Create Entity](/api-reference/entities/create-entity)
           (`POST …/entities/quote`): send the draft's whole `data` with your
           edits applied (for an endorsement, change only the fields that change
           and keep the rest as generated), and set two fields the draft leaves
           `null` unless your Conversion Rules write them: `referencingPolicy`, the
           policy's id, and the change's date in `endorsementEffectiveDate`,
           `cancellationEffectiveDate` or `reinstatementDate`. Use the
           `effectiveDate` you generated with, written the way the quote writes
           `policyStartDate`, for example
           `{"date": "2026-12-15", "timezone": "America/New_York"}`. An endorsement
           generated with an `endDate` also sets `endorsementEndDate`; without it
           the endorsement runs to `policyEndDate`.
        3. For an endorsement, rate the quote with
           [Rate Saved Quote by Id](/api-reference/field-model-rating/rate-saved-quote-by-id),
           which returns the rating without saving it on the quote (a rating that
           fails is still a `200`, with `diagnostics` and no `data`), and save the
           rating outputs from its `data` with
           [Update Entity](/api-reference/entities/update-entity). Don't rate a
           cancellation or reinstatement (it returns `400`): its draft already has
           the pricing the platform derives.
        4. Bind it with [Bind
        Quote](/api-reference/field-model-policy-transactions/bind-quote)
           and `{"invoices": "generate"}`, or prepare its plan with the
           [quote invoicing](/api-reference/invoicing/quote-invoicing) endpoints and
           bind with `{"invoices": "saved"}`.

        Saving a change quote without `referencingPolicy` is refused. Without
        its

        change date it saves, but

        [Generate Quote
        Invoices](/api-reference/policy-invoicing/generate-quote-invoices)

        and [Attach Quote Invoice
        Plan](/api-reference/policy-invoicing/attach-quote-invoice-plan)

        refuse it with `400 finv2-invalid-quote-transaction-metadata`, and its
        bind

        returns `400`.

        `validationIssues` reports neither field, because a bind by value takes

        the policy and the date from its own request.


        **What produces the data.** Your company's configured Conversion Rules
        for

        (`POLICY_TO_QUOTE`, the requested `transactionType`) are evaluated

        server-side against a single resolved segment of the source policy. Each
        rule

        writes one destination field on the Quote. The rules are part of your

        field-model configuration — what carries between a policy and a quote is

        authored and reviewable, not inferred.


        **The data is the finished draft.** It has every field your Quote

        configuration declares, with every calculated field worked out as a save

        would, `fullTermBillingInfo` included (null while policy invoicing is

        disabled). A field nothing fills is `null`. A value that needs a saved
        quote,

        such as a generated quote number, is `null` until the quote is saved.

        Nothing is saved. `quoteType` is set from `transactionType` — `ENDORSE`

        gives `endorsement`, `RENEW` gives `renewal`, `CANCEL` gives

        `cancellation` and `REINSTATE` gives `reinstatement` — whatever your
        rules

        write, so calculated fields that read it are worked out for that

        transaction. A field you must supply that the draft lacks is reported in

        `validationIssues` and comes back `null`. If a value fails its field's
        type

        check, the calculated fields are not worked out and the finding names
        the

        field.


        **Which segment of the policy is read**, per transaction type — always

        against the policy's latest committed version:


        | `transactionType` | Segment read |

        | --- | --- |

        | `ENDORSE` | the segment covering `effectiveDate` |

        | `CANCEL` | the segment covering `effectiveDate` |

        | `REINSTATE` | the segment covering `effectiveDate` on the cancelled
        version |

        | `RENEW` | the last segment of the expiring term |


        **Four transaction types, and why `NEW_BUSINESS` is not one of them.**
        This

        operation converts *from* a policy, and new business has no source
        policy to

        convert from. New business is fully supported at bind: compose the field
        bag

        yourself and post it, exactly as you do today.


        **Concurrency.** `sourcePolicy.policyVersion` is the version the
        returned bag

        was derived from. Echo it as `expectedPolicyVersion` on the bind request
        and

        the bind is refused with a `409` if the policy moved while your user was

        editing. That is the entire concurrency contract — the server holds
        nothing

        on your behalf.


        **`200` with findings vs. an error.** The dividing rule is FIXABILITY,
        not

        severity. Anything your user can fix by editing the returned draft comes
        back

        as a `200` with entries in `validationIssues` and a usable `data` bag.

        Anything they cannot fix by editing — an unknown policy, a policy in the

        wrong state for the transaction, missing or failing Conversion Rules —
        is a

        structured error with no draft at all.


        Conversion uses the company’s explicitly authored rules. Missing
        required

        configuration is an error; matching field names do not supply a
        fallback.


        **Required permission:** the requested `transactionType`'s own
        permission —

        `policy.endorse`, `policy.cancel`, `policy.reinstate` or `policy.renew`.

        Generating is the read half of authoring that transaction.
      operationId: generateQuote
      parameters:
        - $ref: '#/components/parameters/companyId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - policyId
                - effectiveDate
                - transactionType
              properties:
                policyId:
                  type: string
                  format: uuid
                  description: The source policy to convert from.
                  example: 550e8400-e29b-41d4-a716-446655440000
                effectiveDate:
                  type: string
                  format: date
                  description: >
                    The transaction's effective date. Selects which segment of
                    the

                    source policy is read (see the table above) and is readable
                    by a

                    Conversion Rule as `transaction.effectiveDate`.
                  example: '2026-06-01'
                transactionType:
                  type: string
                  enum:
                    - ENDORSE
                    - CANCEL
                    - REINSTATE
                    - RENEW
                  description: >
                    Which transaction the generated quote would start.
                    `NEW_BUSINESS`

                    is not accepted here — it has no source policy to convert
                    from.
                  example: ENDORSE
                endDate:
                  type: string
                  format: date
                  description: >
                    An endorsement's optional term end date, readable by a
                    Conversion

                    Rule as `transaction.endDate`. `null` in that scope for
                    every

                    other transaction type.
                  example: '2026-12-31'
            examples:
              endorsement:
                summary: Generate an endorsement draft effective mid-term
                value:
                  policyId: 550e8400-e29b-41d4-a716-446655440000
                  effectiveDate: '2026-06-01'
                  transactionType: ENDORSE
              renewal:
                summary: Generate a renewal draft
                value:
                  policyId: 550e8400-e29b-41d4-a716-446655440000
                  effectiveDate: '2027-01-01'
                  transactionType: RENEW
      responses:
        '200':
          description: |
            The editable, unpersisted Quote data with its provenance. Returned
            whether or not `validationIssues` is empty — a non-empty list still
            carries a usable draft. Nothing was persisted.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - sourcePolicy
                  - effectiveWindow
                  - validationIssues
                properties:
                  data:
                    type: object
                    description: >
                      The finished Quote draft, in the same flat shape you would

                      `POST` to bind: every declared Quote field, with
                      `quoteType`

                      set from `transactionType`, calculated fields worked out,
                      and

                      `null` where nothing fills a field or a value needs a
                      saved

                      quote. Edit it and send it on; it exists nowhere on the

                      server.
                    additionalProperties: true
                  sourcePolicy:
                    type: object
                    required:
                      - policyId
                      - policyVersion
                    properties:
                      policyId:
                        type: string
                        format: uuid
                      policyVersion:
                        type: integer
                        description: >
                          The policy version this draft was derived from. Echo
                          it as

                          `expectedPolicyVersion` on bind to be refused with a
                          `409`

                          if the policy moved in the meantime.
                  effectiveWindow:
                    type: object
                    description: The coverage window of the source segment that was read.
                    required:
                      - startDate
                      - endDate
                    properties:
                      startDate:
                        type: string
                        format: date
                      endDate:
                        type: string
                        format: date
                  validationIssues:
                    type: array
                    description: >
                      What the draft's own checks find in `data`, such as a
                      field

                      you must supply or a value that fails its field's type

                      check. Empty means nothing is left to fix for a bind by

                      value. A draft you

                      save as a quote also needs `referencingPolicy` and its
                      change

                      date, which this list does not report.
                    items:
                      type: object
                      required:
                        - problemCode
                        - message
                        - path
                      properties:
                        problemCode:
                          type: string
                          description: >-
                            Stable machine-readable classification of the
                            finding.
                        message:
                          type: string
                          description: The message from the failure site, for display.
                        path:
                          type: string
                          description: >
                            The dot-joined field path the finding names. Empty
                            for a

                            whole-entity finding.
              examples:
                cleanEndorsementDraft:
                  summary: A clean endorsement draft
                  value:
                    data:
                      quoteType: endorsement
                      quoteNumber: null
                      quoteStatus: inProgress
                      policyType: GL
                      effectiveDate: '2026-06-01'
                      primaryInsured:
                        id: 550e8400-e29b-41d4-a716-446655440002
                        exposureName: Acme Co
                      primaryInsuredName: Acme Co
                      description: null
                      fullTermBillingInfo: null
                      referencingPolicy: null
                      endorsementEffectiveDate: null
                    sourcePolicy:
                      policyId: 550e8400-e29b-41d4-a716-446655440000
                      policyVersion: 4
                    effectiveWindow:
                      startDate: '2026-01-01'
                      endDate: '2026-12-31'
                    validationIssues: []
                draftNeedingEdits:
                  summary: A draft with a value that fails its field's type check
                  description: >
                    A rule wrote a number to a text field. The value comes back

                    `null` beside its finding, and calculated fields are not
                    worked

                    out until the draft passes the type check.
                  value:
                    data:
                      quoteType: endorsement
                      policyType: GL
                      effectiveDate: '2026-06-01'
                      primaryInsured:
                        id: 550e8400-e29b-41d4-a716-446655440002
                        exposureName: Acme Co
                      description: null
                      fullTermBillingInfo: null
                    sourcePolicy:
                      policyId: 550e8400-e29b-41d4-a716-446655440000
                      policyVersion: 4
                    effectiveWindow:
                      startDate: '2026-01-01'
                      endDate: '2026-12-31'
                    validationIssues:
                      - problemCode: INVALID_CANONICAL_VALUE
                        message: >-
                          Text value at "description" must be trimmed string |
                          null.
                        path: fieldModelV1Data.description
        '400':
          description: >
            The request body is malformed — a missing or non-UUID `policyId`, an

            `effectiveDate` that is not an ISO date, or a `transactionType`
            outside

            the four policy-backed types.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                newBusinessRejected:
                  summary: NEW_BUSINESS has no source policy to convert from
                  value:
                    error:
                      code: VALIDATION_ERROR
                      message: >-
                        transactionType: Invalid option: expected one of
                        "ENDORSE"|"CANCEL"|"REINSTATE"|"RENEW"
                      userMessages:
                        - >-
                          Invalid option: expected one of
                          "ENDORSE"|"CANCEL"|"REINSTATE"|"RENEW"
                      details:
                        - field: transactionType
                          message: >-
                            Invalid option: expected one of
                            "ENDORSE"|"CANCEL"|"REINSTATE"|"RENEW"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: The key lacks the requested transaction type's permission.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: No policy with that id exists for this company.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                policyNotFound:
                  summary: No policy with that id
                  value:
                    error:
                      code: NOT_FOUND
                      message: Policy 550e8400-e29b-41d4-a716-446655440000 not found
                      userMessages:
                        - Policy 550e8400-e29b-41d4-a716-446655440000 not found
        '409':
          description: >
            The source policy cannot supply a snapshot for this transaction: it
            has

            no committed version, no segment covers `effectiveDate`, or a

            `REINSTATE` was asked of a policy that is not cancelled at that
            date.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                notCancelled:
                  summary: Reinstating a policy that is not cancelled
                  value:
                    error:
                      code: Conflict
                      message: >-
                        Policy 550e8400-e29b-41d4-a716-446655440000 must be
                        cancelled at reinstatement date 2026-06-01 — current
                        status is "active"
                      userMessages:
                        - >-
                          Policy 550e8400-e29b-41d4-a716-446655440000 must be
                          cancelled at reinstatement date 2026-06-01 — current
                          status is "active"
        '422':
          description: >
            The company's configuration cannot produce this conversion: no
            Conversion

            Rules are declared for (`POLICY_TO_QUOTE`, `transactionType`), or a
            rule's

            expression failed at evaluation. Both are configuration faults — a
            caller

            cannot fix them by editing a draft, so no draft is returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                noRules:
                  summary: No conversion rules declared for this transaction type
                  value:
                    error:
                      code: no-conversion-rules-configured
                      message: >-
                        No POLICY_TO_QUOTE conversion rules are configured for
                        transaction type ENDORSE
                ruleFailed:
                  summary: A conversion rule expression failed
                  value:
                    error:
                      code: conversion-rule-evaluation-failed
                      message: >-
                        Conversion rule POLICY_TO_QUOTE x ENDORSE ->
                        "effectiveDate" failed to evaluate
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  parameters:
    companyId:
      name: companyId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Company identifier
  schemas:
    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
    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.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.