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

# Create Policy

> Creates a new policy directly, primarily for historical imports where policies
need to be created without going through the quote→bind wizard flow.

**Workflow:**
1. Create insureds first via `POST /insureds`
2. Create the policy with insured references via this endpoint
3. The endpoint creates insured snapshots with the provided ratingInfo

**Required fields:**
- `referenceId` - Policy number (must be unique)
- `startsAtDate`, `endsAtDate` - Coverage dates
- `type` - Policy type (C, N, T, O, P, S, Q, R, A)
- `billingPeriod` - Billing frequency
- `exposures` - At least one exposure with exactly one having `role: "primary"`
- `coverages` - At least one coverage with valid `coverageTypeId`

**Required permission:** `company.policy:create`




## OpenAPI

````yaml /openapi/generated-external-api.yaml post /api/external/companies/{companyId}/policies
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://app.aiinsurance.io
    description: Production
security:
  - ApiKeyAuth: []
paths:
  /api/external/companies/{companyId}/policies:
    post:
      tags:
        - Policies
      summary: Create Policy
      description: >
        Creates a new policy directly, primarily for historical imports where
        policies

        need to be created without going through the quote→bind wizard flow.


        **Workflow:**

        1. Create insureds first via `POST /insureds`

        2. Create the policy with insured references via this endpoint

        3. The endpoint creates insured snapshots with the provided ratingInfo


        **Required fields:**

        - `referenceId` - Policy number (must be unique)

        - `startsAtDate`, `endsAtDate` - Coverage dates

        - `type` - Policy type (C, N, T, O, P, S, Q, R, A)

        - `billingPeriod` - Billing frequency

        - `exposures` - At least one exposure with exactly one having `role:
        "primary"`

        - `coverages` - At least one coverage with valid `coverageTypeId`


        **Required permission:** `company.policy:create`
      operationId: createPolicy
      parameters:
        - $ref: '#/components/parameters/companyId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePolicyRequest'
            examples:
              minimal:
                summary: Minimal policy creation
                value:
                  referenceId: POL-2025-001
                  startsAtDate: '2025-01-01'
                  endsAtDate: '2026-01-01'
                  type: C
                  billingPeriod: annual
                  exposures:
                    - insuredId: 550e8400-e29b-41d4-a716-446655440200
                      role: primary
                      joinDate: '2025-01-01'
                      terminationDate: '2026-01-01'
                  coverages:
                    - coverageTypeId: 550e8400-e29b-41d4-a716-446655440300
              withRatingInfo:
                summary: Policy with rating info
                value:
                  referenceId: POL-2025-002
                  startsAtDate: '2025-01-01'
                  endsAtDate: '2026-01-01'
                  type: C
                  billingPeriod: annual
                  description: Professional Liability Policy
                  premium: 1500000
                  coverageTimezone: America/New_York
                  brokerId: 550e8400-e29b-41d4-a716-446655440400
                  exposures:
                    - insuredId: 550e8400-e29b-41d4-a716-446655440200
                      role: primary
                      joinDate: '2025-01-01'
                      terminationDate: '2026-01-01'
                      ratingInfo:
                        revenue: 5000000
                        employees: 25
                        yearsInBusiness: 10
                    - insuredId: 550e8400-e29b-41d4-a716-446655440201
                      role: additional
                      joinDate: '2025-01-01'
                      terminationDate: '2026-01-01'
                  coverages:
                    - coverageTypeId: 550e8400-e29b-41d4-a716-446655440300
                      limits:
                        - limitName: perClaim
                          amount: 1000000
                        - limitName: aggregate
                          amount: 2000000
                      deductible: 10000
                      retroactiveDate: '2020-01-01'
              withExposureOverrides:
                summary: Policy with per-insured coverage overrides
                value:
                  referenceId: POL-2025-003
                  startsAtDate: '2025-01-01'
                  endsAtDate: '2026-01-01'
                  type: C
                  billingPeriod: annual
                  premium: 2500000
                  coverageTimezone: America/New_York
                  exposures:
                    - insuredId: 550e8400-e29b-41d4-a716-446655440200
                      role: primary
                      joinDate: '2025-01-01'
                    - insuredId: 550e8400-e29b-41d4-a716-446655440201
                      role: additional
                      joinDate: '2025-03-01'
                  coverages:
                    - coverageTypeId: 550e8400-e29b-41d4-a716-446655440300
                      limits:
                        - limitName: perClaim
                          amount: 1000000
                        - limitName: aggregate
                          amount: 2000000
                      deductible: 10000
                      retroactiveDate: '2020-01-01'
                      exposureOverrides:
                        - insuredId: 550e8400-e29b-41d4-a716-446655440201
                          limits:
                            - limitName: perClaim
                              amount: 500000
                            - limitName: aggregate
                              amount: 1000000
                          deductible: 25000
                          retroactiveDate: '2023-01-01'
      responses:
        '201':
          description: Policy created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: The ID of the created policy
              examples:
                success:
                  summary: Policy created
                  value:
                    id: 550e8400-e29b-41d4-a716-446655440100
        '400':
          description: Bad Request - Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingReferenceId:
                  summary: Missing required field
                  value:
                    error:
                      code: KeyMissing
                      message: 'referenceId: Required keys were missing'
                      details:
                        - field: referenceId
                          message: Required keys were missing
                duplicatePolicyNumber:
                  summary: Policy number already exists
                  value:
                    error:
                      code: DuplicatePolicyNumber
                      message: A policy with number 'POL-2025-001' already exists
                noPrimaryInsured:
                  summary: No primary insured specified
                  value:
                    error:
                      code: NoPrimaryInsured
                      message: Exactly one exposure with role "primary" is required
                multiplePrimaryInsureds:
                  summary: Multiple primary insureds
                  value:
                    error:
                      code: MultiplePrimaryInsureds
                      message: Only one exposure can have role "primary"
                insuredNotFound:
                  summary: Insured does not exist
                  value:
                    error:
                      code: InsuredNotFound
                      message: >-
                        The following insured IDs do not exist:
                        550e8400-0000-0000-0000-000000000000
                coverageTypeNotFound:
                  summary: Coverage type not enabled
                  value:
                    error:
                      code: CoverageTypeNotFound
                      message: >-
                        The following coverage type IDs are not enabled for this
                        company: 550e8400-0000-0000-0000-000000000000
                brokerNotFound:
                  summary: Broker does not exist
                  value:
                    error:
                      code: BrokerNotFound
                      message: >-
                        Broker with ID '550e8400-0000-0000-0000-000000000000'
                        does not exist
                exposureOverrideInsuredNotFound:
                  summary: Exposure override references unknown insured
                  value:
                    error:
                      code: ExposureOverrideInsuredNotFound
                      message: >-
                        Coverage 0: exposureOverrides[0].insuredId
                        '550e8400-0000-0000-0000-000000000000' is not in the
                        exposures array
                duplicateExposureOverride:
                  summary: Duplicate insuredId in exposure overrides
                  value:
                    error:
                      code: DuplicateExposureOverride
                      message: >-
                        Coverage 0: duplicate insuredId
                        '550e8400-e29b-41d4-a716-446655440200' in
                        exposureOverrides
                exposureOverrideLimitNameMismatch:
                  summary: Override limitName does not match any coverage-level limit
                  value:
                    error:
                      code: ExposureOverrideLimitNameMismatch
                      message: >-
                        Coverage 0: exposureOverrides[0].limits[0].limitName
                        'wrongName' does not match any coverage-level limit
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  parameters:
    companyId:
      name: companyId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Company identifier
  schemas:
    CreatePolicyRequest:
      type: object
      required:
        - referenceId
        - startsAtDate
        - endsAtDate
        - type
        - billingPeriod
        - exposures
        - coverages
      properties:
        referenceId:
          type: string
          description: Policy number (must be unique per company)
        startsAtDate:
          type: string
          format: date
          description: Policy effective start date (YYYY-MM-DD)
        endsAtDate:
          type: string
          format: date
          description: Policy effective end date (YYYY-MM-DD)
        type:
          $ref: '#/components/schemas/PolicyType'
        billingPeriod:
          $ref: '#/components/schemas/BillingPeriod'
        coverageTimezone:
          type: string
          description: >-
            IANA timezone for coverage (e.g., "America/New_York"). Defaults to
            company default.
        description:
          type: string
          description: Policy description
        premium:
          type: number
          description: Total premium in dollars (overrides rating calculation)
        brokerId:
          type: string
          format: uuid
          description: >-
            ID of an existing broker to associate with this policy. Use POST
            /brokers to create a broker first.
        data:
          type: object
          additionalProperties:
            oneOf:
              - type: string
              - type: number
          description: >-
            Custom data fields for this policy. Keys must match fields from GET
            /policies/configuration. Values are strings or numbers.
        exposures:
          type: array
          items:
            $ref: '#/components/schemas/CreatePolicyExposure'
          description: >-
            Exposures (insureds) to add to the policy. Exactly one must have
            role "primary".
          minItems: 1
        coverages:
          type: array
          items:
            $ref: '#/components/schemas/CreatePolicyCoverage'
          description: Coverages to add to the policy
          minItems: 1
    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'
            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
                  message:
                    type: string
                    description: Description of the field error
                    example: Required field is missing
    PolicyType:
      type: string
      description: |
        Type of policy:
        - C: Claims Made
        - N: New Claims Made
        - T: Tail
        - O: Occurrence
        - P: Occurrence + Claims Made
        - S: Split (Half Claims Made/Occurrence)
        - Q: Quota Share
        - R: Occurrence + Claims Made + Tail
        - A: Claims Made (Alternative)
      enum:
        - C
        - 'N'
        - T
        - O
        - P
        - S
        - Q
        - R
        - A
    BillingPeriod:
      type: string
      description: Billing period for the policy
      enum:
        - doNotSendBill
        - annual
        - quarterly
        - monthly
    CreatePolicyExposure:
      type: object
      required:
        - insuredId
        - role
        - joinDate
      properties:
        insuredId:
          type: string
          format: uuid
          description: Insured ID (must already exist in the system)
        role:
          $ref: '#/components/schemas/ExposureRole'
        joinDate:
          type: string
          format: date
          description: Date the insured joins the policy (YYYY-MM-DD)
        terminationDate:
          type: string
          format: date
          description: >-
            Date the insured coverage terminates (YYYY-MM-DD). Optional -
            typically left unset.
        ratingInfo:
          type: object
          additionalProperties: true
          description: Rating data for the insured snapshot
        doNotRate:
          type: boolean
          description: If true, skip rating calculations for this insured
          default: false
    CreatePolicyCoverage:
      type: object
      required:
        - coverageTypeId
      properties:
        coverageTypeId:
          type: string
          description: >-
            ID of a coverage type enabled for the company. Use GET
            /quotes/configuration to find valid coverage type IDs.
        presetId:
          type: string
          description: Preset ID for predefined limit configurations
        limits:
          type: array
          items:
            $ref: '#/components/schemas/CreatePolicyLimit'
          description: Custom limits (if not using preset)
        deductible:
          type: number
          description: Deductible amount in cents
        retroactiveDate:
          type: string
          format: date
          description: Retroactive date for claims-made coverages (YYYY-MM-DD)
        exposureOverrides:
          type: array
          items:
            $ref: '#/components/schemas/CreatePolicyExposureOverride'
          description: >-
            Optional per-insured overrides for this coverage. Each entry sets
            custom limits, deductible, or retroactive date for a specific
            insured, overriding the coverage-level defaults. Insureds without an
            override inherit the coverage-level values.
    ExposureRole:
      type: string
      description: Role of the exposure on the policy
      enum:
        - primary
        - named
        - additional
        - related
    CreatePolicyLimit:
      type: object
      required:
        - limitName
        - amount
      properties:
        limitName:
          type: string
          description: Name of the limit
        amount:
          type: number
          description: Limit amount in cents
    CreatePolicyExposureOverride:
      type: object
      required:
        - insuredId
      properties:
        insuredId:
          type: string
          format: uuid
          description: >-
            ID of an insured from the exposures array. Overrides apply to this
            specific insured on the parent coverage.
        limits:
          type: array
          items:
            $ref: '#/components/schemas/CreatePolicyLimit'
          description: >-
            Per-insured limit overrides. Replaces the coverage-level limits for
            this insured.
        deductible:
          type: number
          description: Per-insured deductible override in dollars
        retroactiveDate:
          type: string
          format: date
          description: Per-insured retroactive date override (YYYY-MM-DD)
  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: UNAUTHORIZED
                  message: Authorization header is required
            bearerTokenNotAllowed:
              summary: Bearer token used instead of API key
              value:
                error:
                  code: UNAUTHORIZED
                  message: External API endpoints require API key authentication
    Forbidden:
      description: Forbidden - Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            insufficientPermissions:
              summary: Insufficient permissions
              value:
                error:
                  code: FORBIDDEN
                  message: Insufficient permissions to perform this action
    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: INTERNAL_ERROR
                  message: An unexpected error occurred. Please try again later.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        API key authentication. Include your API key in the Authorization
        header.

````