Skip to content

Carrier Gateway

The @openinsure/carrier package is the carrier integration layer. It handles appetite evaluation, concurrent multi-carrier submission routing, best-quote selection, and bordereaux SFTP export. It ships with a built-in database of 6 pre-configured carriers.

Every carrier is described by a CarrierProfile:

interface CarrierProfile {
id: string;
name: string;
naic: string;
type: 'admitted' | 'surplus-lines' | 'reinsurer' | 'captive' | 'lloyds';
amBestRating: AMBestRating; // 'A++' | 'A+' | 'A' | 'A-' | 'B++' | ...
appetite: LineOfBusiness[]; // LOBs this carrier writes
admittedStates: string[]; // 2-char state codes ('ALL' for nationwide)
maxLimitPerRisk: number; // in dollars
maxAggregateLimit: number;
minPremium: number;
requiresMGA: boolean; // MGA sponsorship required
}

Six carriers are pre-configured in CARRIER_DB:

CarrierTypeAM BestKey LOBsMax Limit
Lloyd’s Syndicate 2623Surplus-linesACyber, Prof Liability, D&O, Crime$50M
Travelers CommercialAdmitted (all US)A++GL, Property, Auto, WC, Umbrella$25M
Beazley SpecialtySurplus-linesACyber, Prof Liability, Crime, EPL, D&O$25M
Zurich North AmericaAdmitted (most US)A+GL, WC, Auto, Prof Liability, D&O$50M
Markel SpecialtySurplus-linesAGL, Prof Liability, D&O, Crime, Excess, Marine$100M
Hiscox USASurplus-linesAProf Liability, Cyber, D&O, EPL, Crime$10M

Evaluates whether a carrier will write a given risk:

import { checkCarrierAppetite, CARRIER_DB } from '@openinsure/carrier';
const result = checkCarrierAppetite(CARRIER_DB[0], {
lineOfBusiness: 'Cyber',
state: 'CA',
requestedLimit: 5_000_000,
premium: 15_000,
});
// Returns: AppetiteCheckResult
// {
// eligible: true,
// score: 87,
// reasons: [],
// requiredEndorsements: ['CA surplus-lines stamp required'],
// }

Scoring formula:

  • 60% weight: AM Best rating tier (A++ = 100, A+ = 95, A = 90, A- = 85, B++ = 75, …)
  • 40% weight: Limit headroom (requestedLimit / maxLimitPerRisk, capped at 1.0)

A carrier scores 0 and is marked ineligible if:

  • LOB is not in carrier.appetite
  • State is not in carrier.admittedStates (and carrier is admitted-type)
  • requestedLimit > carrier.maxLimitPerRisk
  • premium < carrier.minPremium

Filters eligible carriers and sorts by appetite score descending:

const ranked = rankCarriers(Object.values(CARRIER_DB), input);
// [{ carrier, score, eligible, reasons }, ...] — highest score first

Lookup a carrier by internal ID or NAIC code:

const carrier = findCarrier('26298'); // NAIC code
const carrier = findCarrier('travelers-commercial'); // internal ID

The CarrierGateway routes submissions to one or more carriers concurrently and selects the best quote.

import { createCarrierGateway } from '@openinsure/carrier';
const gateway = createCarrierGateway();
const response = await gateway.submitToCarrier('travelers-commercial', {
carrierId: 'travelers-commercial',
submissionId: 'sub_abc123',
lob: 'Commercial GL',
state: 'NC',
effectiveDate: '2026-07-01',
expirationDate: '2027-07-01',
insuredName: 'Acme Hardware LLC',
requestedLimit: 1_000_000,
deductible: 5_000,
naics: '444130',
premium: 4_800,
});
// response.status: 'quoted' | 'pending' | 'declined' | 'referred' | 'error'
// response.quotedPremium: 4650

Submit to multiple carriers concurrently with Promise.allSettled — one carrier timeout or error does not block the others:

const result = await gateway.submitToMultiple(
['travelers-commercial', 'zurich-na', 'markel-specialty'],
request
);
// result.bestQuote — lowest premium quoted response
// result.responses — all carrier responses
// result.errors — any carriers that errored

Submit to all carriers that pass appetite checking automatically:

const result = await gateway.submitToEligible(request, CARRIER_DB);
// Runs checkCarrierAppetite() for each carrier, submits to eligible ones only
StatusDescription
pendingSubmission received, awaiting underwriter review
quotedPremium quoted — quotedPremium is populated
declinedDeclined — declineReason is populated
referredReferred to senior underwriter
errorCarrier API error or timeout

Generates a pipe-delimited CSV for bordereaux submission to carriers or reinsurers:

import { generateBordereauxCSV } from '@openinsure/carrier';
const csv = generateBordereauxCSV([
{
policyNumber: 'GL-2026-00451',
insuredName: 'Acme Hardware LLC',
effectiveDate: '2026-01-01',
expirationDate: '2027-01-01',
grossPremium: 12_500,
commissionAmount: 1_875,
netPremium: 10_625,
state: 'NC',
lob: 'GL',
transactionType: 'New Business',
},
]);

CSV headers: PolicyNumber | InsuredName | EffectiveDate | ExpirationDate | GrossPremium | CommissionAmount | NetPremium | State | LOB | TransactionType

transmitBordereauxSftp(csvContent, fileName, config)

Section titled “transmitBordereauxSftp(csvContent, fileName, config)”

Transmits a bordereaux CSV to a carrier’s SFTP endpoint:

const result = await transmitBordereauxSftp(csv, 'bordereaux-2026-03.csv', {
host: 'sftp.carrier.com',
port: 22,
username: 'mga_user',
privateKey: env.CARRIER_SFTP_KEY,
});
// { success: true, bytesTransferred: 4096, path: '/upload/bordereaux/bordereaux-2026-03.csv' }

The gateway ships mock adapters for testing without real carrier APIs:

import { createCarrierGateway, createMockAdapter } from '@openinsure/carrier';
const gateway = createCarrierGateway();
gateway.registerAdapter(
'travelers-commercial',
createMockAdapter('travelers-commercial', 'Travelers', { behavior: 'autoQuote', latencyMs: 200 })
);
// Behaviors: 'autoQuote' | 'declineAll' | 'refer'

All API integration tests use mock adapters — no real carrier API calls in CI.

MGA Overview

Delegated authority, program management, and bordereaux.

Reinsurance

Treaty cession, XOL, and aggregate calculations.