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

# Create Policy

> Create a single policy declaratively

Creates a single policy without a file upload. Only `policyNumber` and `riskStateCode` are required. Everything else is optional and can be added later with [Update Policy](/api-reference/v1/policies/update-policy).

<Note>
  A policy record in Turris represents bound business. The available `currentStatus` values (`bound`, `active`, `expired`, `cancelled`, `non renewed`) are all lifecycle states after binding, so there is no quote or pre-bind state. `policyNumber` is required because it is the grouping key that ties transactions together, not because Turris re-checks that the policy is bound.
</Note>

## Descriptive fields and association ids

Most fields on this endpoint are **descriptive**: the raw values your system already holds, stored verbatim on the policy record. Two fields are different. `downstreamEntityAssociationId` and `productId` are **association ids**, meaning Turris record ids that create a hard link between the policy and an entity you already have in Turris.

The distinction matters because compliance work runs on the links, not on the strings. Turris can only check whether an agency was licensed and appointed in the risk state on the effective date once the policy is linked to a specific downstream entity association. An agency name on its own is text.

You can supply either kind, or both. They do different jobs.

### Identifying the agency

| Field                                                                                               | Kind           | What it does                                                                                                                                                                                                       |
| --------------------------------------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `downstreamEntityAssociationId`                                                                     | Association id | Links the policy directly to that agency and stamps `entityMatchStatus` = `user confirmed`. No matching runs, and a later matching pass leaves confirmed policies alone unless an operator explicitly resets them. |
| `agencyName`                                                                                        | Descriptive    | Stored on the record, shown in the Turris UI, used by name filters, and the primary matcher signal when no association id was supplied                                                                             |
| `agencyNpn`, `agencyFein`, `agencyLicenseNumber` + `agencyLicensedStateCode`, `producerCode`, `npn` | Descriptive    | Additional matcher signals, each stronger than the name alone                                                                                                                                                      |

Get the `downstreamEntityAssociationId` from [List Associations](/api-reference/v1/downstream-entity-associations/list-associations). It resolves internally to the downstream entity and the upstream/downstream association pair.

**Send the id when you have it.** It is exact, immediate, and immune to spelling drift. If your system stores a Turris association id against each agency, send it on every create.

**Send the descriptive fields when you do not.** A policy created without an association id is stored with `entityMatchStatus` = `unmatched`, and a later matching run resolves it against your downstream entity roster in this order:

1. A previously confirmed mapping for that normalized agency name
2. `producerCode`
3. `agencyNpn`, then the generic `npn`
4. `agencyFein`
5. `agencyLicenseNumber` combined with `agencyLicensedStateCode`
6. Exact agency name against legal name or DBA
7. Normalized agency name, ignoring suffixes such as Inc, LLC, Ltd, Corp

Anything the deterministic layers cannot settle goes to AI matching against your agency roster. Anything still unresolved is flagged for manual review in the Turris app.

**Send both when you can.** They do not conflict. The association id governs the link; the descriptive fields are still stored, and they are what a reviewer reads on the policy, what name-based filters query, and what the matcher falls back to if the association is ever cleared. Sending the name alongside the id costs nothing and makes the record legible.

### Identifying the product

The same split applies.

| Field                        | Kind           | What it does                                                                                  |
| ---------------------------- | -------------- | --------------------------------------------------------------------------------------------- |
| `productId`                  | Association id | Links the product and stamps `productMatchStatus` = `user confirmed`                          |
| `productName`, `productCode` | Descriptive    | Stored on the record, and the signals AI product matching uses against your product catalogue |

Get `productId` from [List Products](/api-reference/v1/products/list-products). If your upstream entity has exactly one product, matching assigns it automatically after the agency match and no product matching is needed.

### Carrier and agent fields

`carrierName`, `agentName`, `agentNpn`, `agentLicenseNumber`, `agentLicensedState`, `producerName`, `lineOfBusiness`, `insuredEntityName`, `filingNumber`, `slaNumber` and `externalBillingId` are all descriptive. There is no carrier association id on this endpoint. Agent fields feed agent matching during a matching run but are never required at create time.

## Creating a policy before you have every detail

No descriptive field is required, so a partial create is a supported flow rather than a workaround. A common pattern is to create the policy as soon as the policy number and risk state are known, then PATCH in premium, coverage limits, product and agency details as they land.

Get `policyNumber` and `riskStateCode` right at create time. They are the two required fields, and they are also the two [Update Policy](/api-reference/v1/policies/update-policy) does not accept, so neither can be changed afterwards. `createInitialTransaction` is likewise create-only; attach later transactions with [Create Transaction](/api-reference/v1/policy-transactions/create-transaction) instead.

Every other field on this endpoint can be set later through PATCH, and passing `null` for an association id clears it and resets that match status to `unmatched`.

<Warning>
  Creating a policy through this endpoint does not by itself queue a matching run. Policies created with `entityMatchStatus` = `unmatched` stay unmatched until matching is started from the Turris app, or until you attach the association explicitly with [Update Policy](/api-reference/v1/policies/update-policy). If your integration cannot supply `downstreamEntityAssociationId`, expect an operator to run matching on the unmatched queue.
</Warning>

<Note>
  `currentStatus` defaults to `bound` and is recomputed from transactions once any are attached. See [Create Transaction](/api-reference/v1/policy-transactions/create-transaction).
</Note>

## Creating the initial transaction

By default the policy is created transaction-less (`transactionCount` = 0). Set `createInitialTransaction` to `true` to atomically create the policy's first transaction alongside it in one operation. The transaction is inferred, not supplied:

| Field                   | Inferred value                                                            |
| ----------------------- | ------------------------------------------------------------------------- |
| `policyTransactionType` | `new`                                                                     |
| `policyTransactionDate` | `effectiveDate` when supplied, otherwise today                            |
| descriptive fields      | inherited from the policy body                                            |
| agency match            | mirrors the policy's confirmed agency when present, otherwise `unmatched` |
| agents                  | none                                                                      |

When the flag is `true`, `transactionCount` becomes 1, `latestTransactionId` points at the new transaction, and `currentStatus` is derived from that transaction rather than the request body. Both writes commit together; either one failing rolls back the whole request. Defaults to `false` when omitted, leaving the create behavior unchanged.

## Response Shape

<Note>
  All successful responses are wrapped in the standard response envelope. See [Request/Response Conventions](/guides/request-response).
</Note>

```json theme={null}
{
  "statusCode": 201,
  "data": {
    "_id": "6650a1b2c3d4e5f6a7b8c9d0",
    "policyNumber": "POL-2025-001",
    "currentStatus": "bound",
    "riskStateCode": "CA",
    "entityMatchStatus": "unmatched",
    "productMatchStatus": "unmatched",
    "matchedDownstreamEntities": [],
    "transactionCount": 0,
    "createdAt": "2025-01-15T10:30:00.000Z",
    "updatedAt": "2025-01-15T10:30:00.000Z"
  },
  "timestamp": "2025-01-15T10:30:00.000Z"
}
```

## Error Scenarios

### Bad Request (400)

Returned when the body fails validation (missing `policyNumber` or `riskStateCode`, invalid enum value, or malformed association id).

```json theme={null}
{
  "statusCode": 400,
  "errorType": "validation_error",
  "errorMessage": ["riskStateCode should not be empty"],
  "requestId": "dev-abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}
```

### Association Not Found (404)

Returned when a supplied `productId` or `downstreamEntityAssociationId` does not exist for your upstream entity.

```json theme={null}
{
  "statusCode": 404,
  "errorType": "not_found",
  "errorMessage": ["Product not found"],
  "requestId": "dev-abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}
```

### Duplicate Policy (409)

Returned when a policy with the same `policyNumber` already exists for your upstream entity.

```json theme={null}
{
  "statusCode": 409,
  "errorType": "conflict",
  "errorMessage": ["A policy with this policy number already exists"],
  "requestId": "dev-abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}
```

### Unauthorized (401)

Missing or invalid authentication token. See [Authentication](/authentication).

## Idempotency

This endpoint supports idempotency. If you include an `idempotency-key` header, duplicate requests within **1 hour** return the original response without creating a second policy. See [Idempotency](/guides/idempotency).


## OpenAPI

````yaml openapi/v1.json POST /v1/policies
openapi: 3.0.0
info:
  title: Turris Public API
  description: API for managing insurance compliance data
  version: 1.0.0
  contact: {}
servers:
  - url: https://public.api.live.turrisfi.com
    description: Production
  - url: https://public.api.sandbox.turrisfi.com
    description: Sandbox
security: []
tags: []
paths:
  /v1/policies:
    post:
      tags:
        - policies
      operationId: PoliciesController_createPolicy_v1
      parameters:
        - name: idempotency-key
          in: header
          description: UUID to ensure idempotent request processing
          required: false
          schema:
            type: string
            example: 550e8400-e29b-41d4-a716-446655440000
        - name: x-idempotency-key
          in: header
          description: Alternative UUID header for idempotent request processing
          required: false
          schema:
            type: string
            example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePolicyDto'
      responses:
        '201':
          description: Policy created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/PolicyApiResponse'
                  requestId:
                    type: string
                    description: Unique request identifier
                    example: dev-2c5e7cf2-9acf-4c8c-ab2f-b81f39d775a8
                  timestamp:
                    type: string
                    description: Response timestamp
                    example: '2025-11-12T20:49:03.293Z'
                required:
                  - data
                  - requestId
                  - timestamp
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
        '401':
          description: Invalid or missing auth token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
        '404':
          description: Supplied product or agency association not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
        '409':
          description: A policy with this policy number already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
components:
  schemas:
    CreatePolicyDto:
      type: object
      properties:
        policyNumber:
          type: string
          description: Policy number that groups transactions into a single policy
          example: POL-2025-001
        riskStateCode:
          type: string
          description: US state code where the risk is located
          example: CA
        currentStatus:
          type: string
          description: >-
            Initial lifecycle status. Recomputed from transactions once any are
            attached; defaults to "bound".
          example: bound
          enum:
            - bound
            - active
            - expired
            - cancelled
            - non renewed
        insuredEntityName:
          type: string
          description: Name of the insured party
          example: Example Corp
        agencyName:
          type: string
          description: >-
            Agency name as your system holds it. Stored verbatim and used as the
            primary matching signal when downstreamEntityAssociationId is not
            supplied. Send both when you have the association id: the id creates
            the link, this field stays the human-readable label.
          example: Premier Insurance Agency
        carrierName:
          type: string
          description: Insurance carrier name
          example: National Insurance Co
        effectiveDate:
          type: string
          description: Policy effective date (ISO 8601)
          example: '2025-01-15T00:00:00.000Z'
        expiryDate:
          type: string
          description: Policy expiration date (ISO 8601)
          example: '2026-01-15T00:00:00.000Z'
        premiumAmountInUSD:
          type: number
          description: Premium amount in USD
          example: 5000
        aggregateCoverageInUSD:
          type: number
          description: Aggregate coverage limit in USD
          example: 1000000
        coveragePerClaimInUSD:
          type: number
          description: Per-claim coverage limit in USD
          example: 500000
        lineOfBusiness:
          type: string
          description: Line of business
          example: Commercial Lines
        licenseNumber:
          type: string
          description: License number
          example: LIC-001
        npn:
          type: string
          description: National Producer Number
          example: '11223344'
        producerName:
          type: string
          description: Producing agent name
          example: Jon Doe
        producerCode:
          type: string
          description: Producer identifier code
          example: PROD-001
        productName:
          type: string
          description: >-
            Product name as your system holds it. Stored verbatim and used as a
            matching signal against your product catalogue when productId is not
            supplied.
          example: General Liability
        productCode:
          type: string
          description: Product code
          example: GL-100
        filingNumber:
          type: string
          description: Filing number
          example: FIL-2025-001
        slaNumber:
          type: string
          description: SLA number
          example: SLA-2025-001
        externalBillingId:
          type: string
          description: External billing identifier
          example: BILL-2025-001
        agencyNpn:
          type: string
          description: Agency National Producer Number
          example: '12345678'
        agencyFein:
          type: string
          description: Agency Federal Employer Identification Number
          example: 12-3456789
        agencyLicenseNumber:
          type: string
          description: Agency state license number
          example: ABC-123456
        agencyLicensedStateCode:
          type: string
          description: State where the agency license was issued
          example: CA
        agentName:
          type: string
          description: Individual agent name
          example: John Smith
        agentNpn:
          type: string
          description: Agent National Producer Number
          example: '87654321'
        agentLicenseNumber:
          type: string
          description: Agent state license number
          example: LIC-789012
        agentLicensedState:
          type: string
          description: State where the agent license was issued
          example: TX
        productId:
          type: string
          description: >-
            Product association. Stamps productMatchStatus = "user confirmed"
            when supplied.
          example: 6650a1b2c3d4e5f6a7b8c9d0
        downstreamEntityAssociationId:
          type: string
          description: >-
            Agency association - the downstreamEntityAssociationId from GET
            /downstream-entity-associations. Resolved to
            upstreamDownstreamAssociationId + downstreamEntityId; stamps
            entityMatchStatus = "user confirmed".
          example: 6650a1b2c3d4e5f6a7b8c9d0
        createInitialTransaction:
          type: boolean
          description: >-
            When true, atomically create the policy first transaction alongside
            the policy. The initial transaction is inferred as type "new", dated
            effectiveDate (or today when absent), and inherits the policy
            descriptive and confirmed-agency fields. transactionCount becomes 1
            and currentStatus is derived from that transaction. Defaults to
            false.
          example: true
      required:
        - policyNumber
        - riskStateCode
    PolicyApiResponse:
      type: object
      properties:
        _id:
          type: string
          description: Unique policy identifier
          example: 6650a1b2c3d4e5f6a7b8c9d0
        upstreamEntityId:
          type: string
          description: Owning upstream entity id
          example: 6650a1b2c3d4e5f6a7b8c9d0
        policyNumber:
          type: string
          description: Policy number
          example: POL-2025-001
        currentStatus:
          type: string
          description: Current lifecycle status
          example: bound
          enum:
            - bound
            - active
            - expired
            - cancelled
            - non renewed
        insuredEntityName:
          type: string
          description: Name of the insured party
          example: Example Corp
        agencyName:
          type: string
          description: Agency name
          example: Premier Insurance Agency
        carrierName:
          type: string
          description: Insurance carrier name
          example: National Insurance Co
        effectiveDate:
          type: string
          description: Policy effective date (ISO 8601)
          example: '2025-01-15T00:00:00.000Z'
        expiryDate:
          type: string
          description: Policy expiration date (ISO 8601)
          example: '2026-01-15T00:00:00.000Z'
        premiumAmountInUSD:
          type: number
          description: Premium amount in USD
          example: 5000
        aggregateCoverageInUSD:
          type: number
          description: Aggregate coverage limit in USD
          example: 1000000
        coveragePerClaimInUSD:
          type: number
          description: Per-claim coverage limit in USD
          example: 500000
        lineOfBusiness:
          type: string
          description: Line of business
          example: Commercial Lines
        licenseNumber:
          type: string
          description: License number
          example: LIC-001
        npn:
          type: string
          description: National Producer Number
          example: '11223344'
        producerName:
          type: string
          description: Producing agent name
          example: Jon Doe
        producerCode:
          type: string
          description: Producer identifier code
          example: PROD-001
        productName:
          type: string
          description: Product name
          example: General Liability
        productCode:
          type: string
          description: Product code
          example: GL-100
        filingNumber:
          type: string
          description: Filing number
          example: FIL-2025-001
        slaNumber:
          type: string
          description: SLA number
          example: SLA-2025-001
        externalBillingId:
          type: string
          description: External billing identifier
          example: BILL-2025-001
        agencyNpn:
          type: string
          description: Agency National Producer Number
          example: '12345678'
        agencyFein:
          type: string
          description: Agency Federal Employer Identification Number
          example: 12-3456789
        agencyLicenseNumber:
          type: string
          description: Agency state license number
          example: ABC-123456
        agencyLicensedStateCode:
          type: string
          description: State where the agency license was issued
          example: CA
        agentName:
          type: string
          description: Individual agent name
          example: John Smith
        agentNpn:
          type: string
          description: Agent National Producer Number
          example: '87654321'
        agentLicenseNumber:
          type: string
          description: Agent state license number
          example: LIC-789012
        agentLicensedState:
          type: string
          description: State where the agent license was issued
          example: TX
        riskStateCode:
          type: string
          description: US state code where the risk is located
          example: CA
        downstreamEntityId:
          type: string
          description: Resolved matched downstream entity (agency) id
          example: 6650a1b2c3d4e5f6a7b8c9d0
        upstreamDownstreamAssociationId:
          type: string
          description: Resolved agency association id
          example: 6650a1b2c3d4e5f6a7b8c9d1
        entityMatchStatus:
          type: string
          description: Agency/entity matching status
          example: user confirmed
          enum:
            - auto matched
            - user confirmed
            - manual review
            - unmatched
        entityMatchConfidence:
          type: number
          description: Entity match confidence (0-1)
          example: 1
        productId:
          type: string
          description: Matched product id
          example: 6650a1b2c3d4e5f6a7b8c9d0
        productMatchStatus:
          type: string
          description: Product matching status
          example: unmatched
          enum:
            - auto matched
            - user confirmed
            - needs clarification
            - unmatched
        productMatchConfidence:
          type: number
          description: Product match confidence (0-1)
          example: 1
        matchedDownstreamEntities:
          description: Confirmed matched downstream entities
          type: array
          items:
            $ref: '#/components/schemas/PolicyMatchedDownstreamEntityResponse'
        latestTransactionId:
          type: string
          description: Id of the most recent transaction
          example: 6650a1b2c3d4e5f6a7b8c9d0
        transactionCount:
          type: number
          description: Number of transactions linked to this policy
          example: 3
        uploadSource:
          type: string
          description: Origin channel of the policy
          example: public api
          enum:
            - upstream entity
            - enterprise
            - public api
            - downstream entity
        columnMappingId:
          type: string
          description: Column-mapping sentinel id
          example: 6650a1b2c3d4e5f6a7b8c9d0
        entityId:
          type: string
          description: Owner entity id
          example: 6650a1b2c3d4e5f6a7b8c9d0
        entityModel:
          type: string
          description: Owner entity model
          example: UpstreamEntity
          enum:
            - UpstreamEntity
            - DownstreamEntity
            - EnterpriseUpstreamEntity
            - EnterpriseDownstreamEntity
            - Agent
            - Admin
            - turris_ops
        isDeleted:
          type: boolean
          description: Soft-delete flag
          example: false
        createdAt:
          type: string
          description: ISO 8601 timestamp when the policy was created
          example: '2025-01-15T10:30:00.000Z'
        updatedAt:
          type: string
          description: ISO 8601 timestamp of the last update
          example: '2025-01-15T10:31:45.000Z'
      required:
        - _id
        - upstreamEntityId
        - policyNumber
        - currentStatus
        - riskStateCode
        - entityMatchStatus
        - productMatchStatus
        - matchedDownstreamEntities
        - transactionCount
        - columnMappingId
        - entityId
        - entityModel
        - isDeleted
        - createdAt
        - updatedAt
    ErrorResponseDto:
      type: object
      properties:
        statusCode:
          type: number
          description: HTTP status code
        requestId:
          type: string
          description: Unique request identifier for debugging
        errorType:
          type: string
          description: >-
            Machine-readable error classification. Branch on this rather than on
            `errorMessage`, which is prose and may change. Authentication
            failures returned by our identity provider are forwarded verbatim,
            so a 401 can carry a code outside this list; treat an unrecognised
            value as a generic failure of its HTTP status.
          enum:
            - conflict
            - contact_not_authorized
            - document_exceeds_page_limit
            - downstream_entity_member_exists
            - duplicate_external_id_error
            - duplicate_member_email
            - duplicate_producer_code_error
            - forbidden
            - gateway_timeout
            - inactive_email
            - internal_server_error
            - invalid_email
            - invalid_email_for_invites
            - invalid_organization_category
            - invalid_organization_slug
            - invalid_phone_number
            - invalid_token
            - invite_limit_reached
            - jwt_invalid
            - m2m_client_not_found
            - not_found
            - organization_already_exists
            - organization_slug_already_used
            - payment_required
            - producer_agreement_required
            - product_feature_subscription_required
            - service_unavailable
            - session_authorization_error
            - some_custom_error_string
            - throttled
            - too_many_requests
            - unauthorized
            - unauthorized_client
            - unexpected_400_stytch_error
            - unexpected_403_stytch_error
            - unexpected_404_stytch_error
            - unexpected_error
            - unexpected_stytch_error
            - unprocessable_entity
            - validation_error
          example: validation_error
        errorMessage:
          description: Array of error messages
          type: array
          items:
            type: string
        timestamp:
          type: string
          description: ISO timestamp when the error occurred
        details:
          type: object
          description: Additional error context
      required:
        - statusCode
        - requestId
        - errorType
        - errorMessage
        - timestamp
    PolicyMatchedDownstreamEntityResponse:
      type: object
      properties:
        downstreamEntityId:
          type: string
          description: Matched downstream entity (agency) id
          example: 6650a1b2c3d4e5f6a7b8c9d0
        upstreamDownstreamAssociationId:
          type: string
          description: Upstream-downstream association id backing the match
          example: 6650a1b2c3d4e5f6a7b8c9d1
        matchSource:
          type: string
          description: Origin of the match
          example: user
          enum:
            - ai
            - user
        matchConfidence:
          type: number
          description: Match confidence (0-1)
          example: 1
        matchedAt:
          type: string
          description: ISO 8601 timestamp when the match was recorded
          example: '2025-01-15T10:30:00.000Z'
      required:
        - downstreamEntityId
        - upstreamDownstreamAssociationId
        - matchSource

````

## Related topics

- [Update Policy](/api-reference/v1/policies/update-policy.md)
- [Create Transaction](/api-reference/v1/policy-transactions/create-transaction.md)
- [Create Agent](/api-reference/v1/agents/create-agent.md)
