Carrier Portal
The Carrier Portal (apps/carrier-portal, oi-sys-carrier) is a Next.js application for insurance carrier operations teams. It gives carriers real-time visibility into their book of business — programs, producers, bordereaux submissions, claims, financial reconciliation, and binding authority matrices — all scoped behind the carrier_admin JWT role.
The Carrier Portal is intentionally read-focused. Carriers can review and approve bordereaux, monitor claims, and track treaty exposures but cannot directly modify underwriting rules, rate tables, or policy records — those operations flow through the API and are gated by delegated authority limits.
URL & Access
| Environment | URL |
|---|---|
| Production | https://carrier.openinsure.dev |
| Local dev | http://localhost:3005 |
Sign In
GET https://auth-dev.openinsure.dev/api/auth/sign-in/microsoft
?callbackURL=https://carrier.openinsure.dev/api/auth/callback
The portal sets the oi_carrier_token httpOnly cookie verified against CARRIER_JWT_SECRET.
Roles & Authorization
| JWT role | Description |
|---|---|
carrier_admin | Full carrier portal access |
superadmin | Platform-wide access |
system | Machine-to-machine (M2M) |
Role enforcement is in apps/carrier-portal/lib/auth.ts. Unauthenticated requests redirect to /login.
Navigation
| Section | Page | Route |
|---|---|---|
| Overview | Dashboard | / |
| Book | Bordereaux | /bordereaux |
| Book | Claims | /claims |
| Book | Programs | /programs |
| Authority | Binding Authority | /authority |
| Finance | Financials | /financials |
| Finance | Reconciliation | /financials/reconciliation |
| Finance | Treaties | /treaties |
| Governance | Audit Log | /audit |
Navigation badges (/api/badges) poll every 60 seconds to show unread counts on Bordereaux and Claims.
Pages
Dashboard (/)
Portfolio KPI overview with four metric cards:
- Gross Written Premium — YTD total across all programs
- Active Policies — Count of in-force policies
- Total Incurred — Paid + reserved across open claims
- Loss Ratio — Incurred / earned premium (warns at > 65%, critical at > 85%)
Below the KPIs: recent bordereaux submissions table (period, status, premium, claims) and program health summary.
API: GET /v1/analytics/mga + GET /v1/bordereaux (most recent 5)
Bordereaux (/bordereaux)
Full listing of bordereaux reports with status badges (pending / reviewed / approved / rejected). Clicking a row opens the detail page with line-level premium and claims data. Reviewers can approve or flag individual submissions.
API: GET /v1/bordereaux + GET /v1/bordereaux/:id
Claims (/claims and /claims/:id)
Claims table with filters by status, loss date, and program. Claim detail shows:
- Reserve history timeline
- Payments & recoveries ledger
- Attachments (ISO forms, photos, reports)
- Adjuster notes and litigation status
Real-time claim status management via ClaimStatusManager component.
API: GET /v1/claims + GET /v1/claims/:id
Programs (/programs and /programs/:id)
Carrier program list with premium-to-limit ratios and loss summaries. Program detail shows the full underwriting guidelines, rate table associations, and historical bordereaux.
Program settings (rate filing status, max aggregate limit, reinsurance attachment) are viewable and can be proposed for edit — changes require admin approval.
Binding Authority (/authority)
Interactive AuthoritySwitch component showing the carrier's delegated authority matrix:
- Per-line authority limits (primary, excess, umbrella)
- State-level admitted/surplus-lines breakdown
- Named peril exclusions and scheduled endorsements
Changes to authority limits flow through the approval queue.
Financials (/financials)
TigerBeetle-backed financial views:
- Income statement — GWP, ceded premium, net earned premium, losses, LAE, expense ratio, combined ratio
- Balance sheet — unearned premium reserve, loss reserve, surplus
Period toggles: MTD / QTD / YTD.
Reconciliation (/financials/reconciliation)
FinancialReconciliationTable component — unreconciled ledger entries between the MGA's books and carrier statements. Entries can be marked reconciled inline.
API: GET /v1/reports/reconciliation + PATCH /v1/reports/reconciliation/:id
Treaties (/treaties and /treaties/:id)
Reinsurance treaty listing and detail. Each treaty shows:
- Type (quota share, XOL, aggregate XL)
- Cession percentage / attachment / limit
- Ceded premium YTD
- Loss recoveries YTD and any outstanding cash calls
Audit Log (/audit)
Immutable activity trail scoped to the carrier's org. Filterable by action type, user, and date range. Exportable to CSV.
API Proxy Allowlist
The portal proxies through apps/carrier-portal/app/api/[...path]/route.ts:
GET /v1/analytics/mga
GET /v1/bordereaux
GET /v1/bordereaux/:id
PATCH /v1/bordereaux/:id/approve
PATCH /v1/bordereaux/:id/reject
GET /v1/claims
GET /v1/claims/:id
PATCH /v1/claims/:id/status
GET /v1/programs
GET /v1/programs/:id
GET /v1/activities
GET /v1/reports/reconciliation
PATCH /v1/reports/reconciliation/:id
GET /v1/reports/financials
GET /v1/treaties
GET /v1/treaties/:id
Any request not in the allowlist returns 403 Forbidden.
Environment Variables
| Variable | Description |
|---|---|
CARRIER_JWT_SECRET | JWT signing secret — set via wrangler secret put |
API_URL | API worker base URL (e.g., https://api.openinsure.dev) |
NEXT_PUBLIC_APP_NAME | "Carrier Portal" — set in wrangler.toml [vars] |
# Set the JWT secret (production)
wrangler secret put CARRIER_JWT_SECRET --name oi-sys-carrier
# Local dev (.env.local)
CARRIER_JWT_SECRET=9d79c38aa7d57bd24a1afe213848b2b935519afb08a3923ac112aed71fd5bc21
API_URL=http://localhost:8787
DEMO_MODE=true
Deployment
The Carrier Portal deploys as an OpenNext Cloudflare Worker (oi-sys-carrier):
cd apps/carrier-portal
npx opennextjs-cloudflare deploy -- --keep-vars
# Or via pnpm filter
pnpm --filter @openinsure/carrier-portal deploy
CI deploys automatically from master when apps/carrier-portal/ or shared packages change.
MGA Overview
Delegated authority, bordereaux, and producer management.
Reinsurance
Treaty management, cession calculations, and cash calls.