Skip to main content
POST
/
v1
/
policies
/
upload
cURL
curl --request POST \
  --url https://public.api.live.turrisfi.com/v1/policies/upload \
  --header 'Content-Type: multipart/form-data' \
  --form file='@example-file'
{
  "data": {
    "uploadId": "6650a1b2c3d4e5f6a7b8c9d0",
    "status": "QUEUED"
  },
  "requestId": "dev-2c5e7cf2-9acf-4c8c-ab2f-b81f39d775a8",
  "timestamp": "2025-11-12T20:49:03.293Z"
}
Upload a policy data file for asynchronous processing. The file headers are validated synchronously — if validation passes, the file is uploaded to storage and a worker job is queued for ingestion. Returns an uploadId that you can poll via Get Upload Status.

Workflow

1

Upload your file

Send a POST /v1/policies/upload request with your CSV or Excel file as multipart/form-data. The response includes an uploadId with status QUEUED.
2

Poll for status

Call GET /v1/policies/uploads/{uploadId} every 3-5 seconds. The status will move from QUEUED to PROCESSING as a worker picks up the file.
3

Handle the result

Stop polling once the status reaches a terminal state: COMPLETED, COMPLETED_WITH_FAILURES, or FAILED. Check the errors array for any row-level failures. Once complete, retrieve your policies via List Policies or Get Policy.

File Requirements

ConstraintValue
FormatsCSV (.csv), Excel (.xlsx)
Max size10 MB
Content-Typemultipart/form-data
Form field namefile

Column Headers

Column headers in your file must exactly match the supported field names listed below. Unrecognized headers are rejected immediately with a 400 response.

Required Columns

These columns must be present in every upload:
Column HeaderDescription
policyNumberUnique identifier that groups transactions into a single policy
riskStateCodeUS state code (e.g., CA, TX, NY)
policyTransactionTypeTransaction lifecycle stage: New, Renewal, Endorsement, Cancellation, or Audit
policyTransactionDateDate the transaction was processed (e.g., 2025-01-15 or 01/15/2025)

Agency Identifier (at least one required)

At least one of these columns must be present for entity matching:
Column HeaderDescription
agencyNameName of the agency — used for AI-powered matching
agencyNpnNational Producer Number — most reliable identifier
agencyFeinFederal Employer Identification Number

Optional Columns

Column HeaderDescription
agencyLicenseNumberState insurance license number of the agency
agencyLicensedStateCodeState where the agency license was issued
agentNameName of the individual agent
agentNpnNPN of the individual agent
agentLicenseNumberState license number of the agent
agentLicensedStateState where the agent license was issued
insuredEntityNameName of the insured party
carrierNameInsurance carrier name
lineOfBusinessLine of business (e.g., Commercial Lines, Property & Casualty)
productNameProduct name for product matching
productCodeProduct code (alternative to product name)
producerNameProducing agent name
producerCodeProducer identifier code
effectiveDatePolicy effective date
expiryDatePolicy expiration date
premiumAmountInUSDPremium amount in USD
aggregateCoverageInUSDAggregate coverage limit
coveragePerClaimInUSDPer-claim coverage limit
filingNumberFiling number
slaNumberSLA number
externalBillingIdExternal billing identifier from the upstream entity billing system
licenseNumberLicense number
npnNPN
upstreamEntityNameUpstream entity name

Success Response

All successful responses are wrapped in the standard response envelope. See Request/Response Conventions.
{
  "statusCode": 201,
  "data": {
    "uploadId": "6650a1b2c3d4e5f6a7b8c9d0",
    "status": "QUEUED"
  },
  "timestamp": "2025-01-15T10:30:00.000Z"
}
FieldTypeDescription
uploadIdstringMongoDB ObjectId — use this to poll Get Upload Status
statusstringAlways QUEUED on successful upload

Error Scenarios

Unsupported File Format (400)

Returned when the file is not CSV or XLSX.
{
  "statusCode": 400,
  "errorType": "validation_error",
  "errorMessage": ["Only CSV and XLSX files are allowed"],
  "requestId": "dev-abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}

Unsupported Column Headers (400)

Returned when any column header doesn’t match a supported field name.
{
  "statusCode": 400,
  "errorType": "validation_error",
  "errorMessage": [
    "Unsupported column headers. Column headers must exactly match the supported field names."
  ],
  "details": {
    "supportedFields": [
      "policyNumber", "riskStateCode", "policyTransactionType", "policyTransactionDate",
      "insuredEntityName", "carrierName", "effectiveDate", "expiryDate",
      "premiumAmountInUSD", "aggregateCoverageInUSD", "coveragePerClaimInUSD",
      "lineOfBusiness", "licenseNumber", "npn", "producerName", "producerCode",
      "productName", "productCode", "filingNumber", "slaNumber", "externalBillingId", "upstreamEntityName",
      "agencyName", "agencyNpn", "agencyFein", "agencyLicenseNumber",
      "agencyLicensedStateCode", "agentName", "agentNpn", "agentLicenseNumber",
      "agentLicensedState"
    ]
  },
  "requestId": "dev-abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}

Missing Required Columns (400)

Returned when one or more required columns are absent.
{
  "statusCode": 400,
  "errorType": "validation_error",
  "errorMessage": ["Missing required columns: riskStateCode, policyTransactionDate"],
  "details": {
    "supportedFields": [
      "policyNumber", "riskStateCode", "policyTransactionType", "policyTransactionDate",
      "insuredEntityName", "carrierName", "effectiveDate", "expiryDate",
      "premiumAmountInUSD", "aggregateCoverageInUSD", "coveragePerClaimInUSD",
      "lineOfBusiness", "licenseNumber", "npn", "producerName", "producerCode",
      "productName", "productCode", "filingNumber", "slaNumber", "externalBillingId", "upstreamEntityName",
      "agencyName", "agencyNpn", "agencyFein", "agencyLicenseNumber",
      "agencyLicensedStateCode", "agentName", "agentNpn", "agentLicenseNumber",
      "agentLicensedState"
    ]
  },
  "requestId": "dev-abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}

Missing Agency Identifier (400)

Returned when none of agencyName, agencyNpn, or agencyFein columns are present.
{
  "statusCode": 400,
  "errorType": "validation_error",
  "errorMessage": [
    "At least one agency identifier column is required: agencyName, agencyNpn, agencyFein"
  ],
  "details": {
    "supportedFields": [
      "policyNumber", "riskStateCode", "policyTransactionType", "policyTransactionDate",
      "insuredEntityName", "carrierName", "effectiveDate", "expiryDate",
      "premiumAmountInUSD", "aggregateCoverageInUSD", "coveragePerClaimInUSD",
      "lineOfBusiness", "licenseNumber", "npn", "producerName", "producerCode",
      "productName", "productCode", "filingNumber", "slaNumber", "externalBillingId", "upstreamEntityName",
      "agencyName", "agencyNpn", "agencyFein", "agencyLicenseNumber",
      "agencyLicensedStateCode", "agentName", "agentNpn", "agentLicenseNumber",
      "agentLicensedState"
    ]
  },
  "requestId": "dev-abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}

No File Uploaded (400)

{
  "statusCode": 400,
  "errorType": "validation_error",
  "errorMessage": ["No file uploaded"],
  "requestId": "dev-abc123",
  "timestamp": "2025-01-15T10:30:00.000Z"
}

File Too Large (413)

Files exceeding 10 MB are rejected by the server before reaching the handler.

Unauthorized (401)

Missing or invalid authentication token. See Authentication.

Idempotency

This endpoint supports idempotency. If you include an idempotency-key header, duplicate requests within 1 hour return the original response without reprocessing. See Idempotency.

Multi-Transaction Policies

Multiple rows sharing the same policyNumber are grouped into a single policy with multiple transactions. For example, a CSV with:
policyNumberpolicyTransactionTypepolicyTransactionDate
POL-001New2025-01-15
POL-001Endorsement2025-03-20
POL-001Renewal2025-06-01
Creates 1 policy with 3 transactions. The policy’s currentStatus is automatically resolved from its transaction history.

Headers

idempotency-key
string

UUID to ensure idempotent request processing

Example:

"550e8400-e29b-41d4-a716-446655440000"

x-idempotency-key
string

Alternative UUID header for idempotent request processing

Example:

"550e8400-e29b-41d4-a716-446655440000"

Body

multipart/form-data
file
file
required

Response

File upload initiated — returns uploadId for polling status

data
object
required
requestId
string
required

Unique request identifier

Example:

"dev-2c5e7cf2-9acf-4c8c-ab2f-b81f39d775a8"

timestamp
string
required

Response timestamp

Example:

"2025-11-12T20:49:03.293Z"