Organization:
Dashboard
Organizations
Products
Customers
Get Quote
Policies
Claims
Audit Logs
Operations
API Docs
Database
Actuarial ↗
Accounting Reinsurance

Portfolio at a Glance

Select an organisation above to load live data
LIVE
Active Policies
Monthly Premium
Total Cover
Customers
Active Products
Quotes

LIFE Insurance Classes

Risk Insurance Individual & group death, disability
Funeral Insurance Up to R100,000 per life
Credit Life Credit-agreement linked
Fund Risk Retirement fund group cover
Life Annuities Regular income for life

NON-LIFE Insurance Classes

Consumer Credit Credit protection (death, disability, retrenchment)
Accident & Health Personal accident, hospital cash
Motor · Property Vehicle damage, theft, buildings
Liability · Legal Expense Third-party liability, legal costs
Travel · Transport · Trade Credit + Agriculture, Engineering, Marine, more

Current Release

v0.9 — Production Preview
Full policy lifecycle — quote, issue, billing, lapse, reinstatement
23-class product wizard (LIFE & NON-LIFE per SA Insurance Act Schedule 2)
Claims workflow — submit, assess, approve/reject, pay
Month-end processing — premium indexation, overdue marking, auto-lapse
Configurable escalation — LEVEL, INDEXED (CPI), STEPPED, REVIEWABLE
Audit logging on all write operations with full request tracing

Platform Health

ALL OPERATIONAL
Policy Issuance & Billing Operational
Claims Processing Operational
Month-End & Indexation Operational
Product Design Wizard Operational
Compliance & Audit Logging Active
Data Platform (Azure PostgreSQL) Connected

Organizations

Design New Product

What type of product do you want to create?

💼

LIFE Insurance

Person-based coverage with age/gender rating

  • ✓ Funeral, Term Life, Whole of Life
  • ✓ Age-banded mortality pricing
  • ✓ Death, disability, critical illness
  • ✓ Long-term coverage
🏠

NON-LIFE Insurance

Asset-based coverage with factor rating

  • ✓ Motor, Property, Liability
  • ✓ Factor-based risk pricing
  • ✓ Damage, theft, accidents
  • ✓ Annual/short-term coverage

This choice determines which product classes and rating methods are available.

Matrix: upload a CSV with rate per factor combination. Multiplicative: set base rate + individual factor relativities.

Products

Rate Template Tools

Update benefit rates for existing launched products. Download the product's CSV template, fill in the rates, then upload to replace the current rate entries.

Add Customer

Customers

Get a Quote

Policies

All
Active
Suspended
Lapsed
Cancelled
Open Claims
Pending Documents
SLA Breaches
Pending Approval

Claims

Claims Reports

Select a report and click Run Report.

Audit Logs

Filter and review all API mutations for the selected organisation. Uses GET /api/v1/audit-logs.

Timestamps are shown in your local time (en-ZA).
Timestamp User Action Resource IP Address Request ID Copy
Select filters and click Search to load audit entries.
Showing 0–0 of 0
Notes: POST = green, PUT/PATCH = amber, DELETE = red. Request ID is truncated to 8 chars; use the copy button to copy the full UUID.

Month-End Operations

Month-end scans active/suspended policies, marks overdue premiums, applies anniversary premium and benefit indexation, and evaluates lapse candidates.

Escalation Config Preview
Run preview to inspect resolved rates before execution.
Month-End Result
Run month-end in dry-run first before applying changes.

Loss Ratio Analysis

Deferred to Stage 2 (UI present; backend call disabled).
Loss Ratio analysis is deferred to Stage 2. UI is visible for preview only.
Product Premiums Claims Loss Ratio
No data yet.

Email Configuration

Manage sender addresses per role. In-memory config resets on server restart.
Role Display Name Email Address Active Actions
Loading senders...

Email Types → Sender Mapping

Email Type Role Sender Email
Loading mappings...
Changes take effect immediately but are not persisted across restarts until backend persistence is added.

API Documentation

Base URL: http://localhost:8080

Organizations

Multi-tenant support. All data is scoped by org_id query parameter.

GET
/api/organizations List all organizations
POST
/api/organizations Create a new organization
Request Body Schema
{
  "name": "string",
  "slug": "string",
  "description": "string"
}

Reference Data

Read-only reference tables seeded from SA Insurance Act Schedule 2.

GET
/api/product-classes List all 23 product classes (6 LIFE + 17 NON_LIFE)
GET
/api/benefit-types List all 21 benefit types (DEATH, DISABILITY, FUNERAL, etc.)
GET
/api/benefit-types/by-class/{class_code} Get allowed benefit types for a specific product class

Rate Tables

Benefit-level rate tables with optional non-life factors (zone, occupation class, vehicle group, smoker).

POST
/api/rate-tables Create a rate table with entries
GET
/api/products/{product_id}/rate-template Download CSV template for product benefits
POST
/api/products/{product_id}/rate-template/upload Upload CSV rates and bind to product benefits
Request Body Schema
{
  "table_name": "Credit Life Main Rates",
  "table_code": "credit-life-main-rates",
  "rate_basis": "PER_MILLE",              // PER_MILLE | PER_CENT | FLAT
  "rating_factors": ["age", "gender"],
  "entries": [
    { "age_from": 18, "age_to": 25, "gender": "MALE", "rate": 0.45 },
    { "age_from": null, "age_to": null, "gender": "UNISEX", "rating_zone": "URBAN", "vehicle_group": "A", "rate": 0.32 },
    { "age_from": 26, "age_to": 30, "gender": "MALE", "smoker_status": "SMOKER", "rate": 0.58 }
  ]
}
Rate Basis:
PER_MILLE: premium = (sum_assured / 1000) * rate
PER_CENT: premium = sum_assured * (rate / 100)
FLAT: premium = rate (fixed amount)

Product Categories

Per-org business groupings under product classes.

GET
/api/product-categories List categories for org
POST
/api/product-categories Create a product category
Request Body Schema
{
  "product_class_id": "uuid",
  "category_code": "INDIVIDUAL_TERM",
  "category_name": "Individual Term Life",
  "description": "string",
  "target_market": "RETAIL | CORPORATE"
}

Products

GET
/api/products List all products
POST
/api/products Create a new product
PUT
/api/products/{id} Update product (AUTO clone, CLONE, or IN_PLACE)
GET
/api/products/{id}/conformance Run white-paper conformance checks for one product
GET
/api/product-conformance/audit Audit all products for conformance gaps (optionally only non-compliant)
POST
/api/product-conformance/remediate Normalize existing product records to baseline conformance defaults (dry-run supported)
Request Body Schema
{
  "name": "string",
  "slug": "string",
  "description": "string",
  "product_type": "TERM_LIFE | WHOLE_LIFE | FUNERAL | DISABILITY | CREDIT_LIFE",
  "pricing_method": "FLAT | RATE_TABLE",
  "base_premium": 199.00,           // for FLAT pricing
  "rate_table": [                   // for RATE_TABLE pricing
    {"age_from": 18, "age_to": 25, "gender": "MALE", "rate_per_thousand": 0.45},
    {"age_from": 18, "age_to": 25, "gender": "FEMALE", "rate_per_thousand": 0.32}
  ],
  "min_entry_age": 18,
  "max_entry_age": 65,
  "min_sum_assured": 10000,
  "max_sum_assured": 5000000,
  "coverage_amount": 100000,        // default for flat rate
  "waiting_period_days": 90,
  "term_type": "FIXED_TERM | WHOLE_OF_LIFE",
  "default_term_years": 20,
  "premium_projection_type": "LEVEL | INDEXED | STEPPED",
  "is_active": true
}
PUT
/api/products/{id}/launch Activate a product (set is_active = true)
DELETE
/api/products/{id} Delete a product

Product Benefits

Per-product benefit definitions with individual pricing (rate table or flat).

GET
/api/products/{product_id}/benefits List all benefits for a product
POST
/api/products/{product_id}/benefits Add a benefit to a product
Request Body Schema
{
  "benefit_type_id": "uuid",
  "benefit_code": "DEATH_MAIN",
  "benefit_name": "Main Member Death Benefit",
  "benefit_amount_type": "SUM_INSURED | FIXED | PERCENTAGE | MULTIPLE",
  "default_amount": 500000,
  "max_amount": 5000000,
  "waiting_period_days": 180,
  "is_mandatory": true,
  "display_order": 1,
  "member_role": "MAIN_MEMBER | SPOUSE | CHILD | PARENT | ALL",
  "rate_table_id": "uuid | null",         // link to rate table for age/gender pricing
  "rate_basis": "PER_MILLE | PER_CENT | FLAT_AMOUNT",
  "flat_premium": 59.00                    // for FLAT pricing (when no rate_table_id)
}
DELETE
/api/product-benefits/{benefit_id} Delete a benefit from a product

Inception Rules

Define what data is required to issue a policy (dynamic form fields at quote/inception).

GET
/api/products/{product_id}/inception-rules List inception rules for a product
POST
/api/products/{product_id}/inception-rules Add inception rule to a product

Customers

GET
/api/customers List all customers
POST
/api/customers Create a new customer
Request Body Schema
{
  "first_name": "string",
  "last_name": "string",
  "email": "string",
  "phone": "string",
  "id_number": "string",           // SA ID number (13 digits)
  "date_of_birth": "YYYY-MM-DD"
}

Quotes & Pricing

POST
/api/quotes/calculate Calculate premium (stateless, no DB write)
Request Body
{
  "product_id": "uuid",
  "customer_id": "uuid",                   // optional - auto-derives age/gender from DOB
  "age": 30,                               // required for LIFE products, optional for NON_LIFE
  "gender": "MALE | FEMALE | UNISEX",
  "sum_assured": 500000,                   // headline SA (used for SUM_INSURED benefits)
  "term_years": 20,                        // optional, default 20
  "rating_inputs": {                       // optional non-life factors
    "rating_zone": "URBAN",
    "occupation_class": "PROFESSIONAL",
    "vehicle_group": "A",
    "smoker_status": "NON_SMOKER"
  },
  "benefit_overrides": [                   // optional per-benefit cover amounts
    { "benefit_code": "DEATH_MAIN", "sum_assured": 500000 },
    { "benefit_code": "FUNERAL_EXP", "sum_assured": 15000 }
  ],
  "excluded_benefits": ["CRITICAL_ILLNESS"],  // optional benefits to exclude
  "insured_lives": [                       // per-role life assured details
    { "relationship": "MAIN_MEMBER", "age": 35, "gender": "MALE",
      "date_of_birth": "1991-03-15", "first_name": "John", "last_name": "Doe" },
    { "relationship": "SPOUSE", "age": 32, "gender": "FEMALE",
      "date_of_birth": "1994-06-20", "first_name": "Jane", "last_name": "Doe" }
  ]
}
Response
{
  "product_id": "uuid",
  "product_name": "Funeral Family Plan",
  "monthly_premium": 310.00,
  "annual_premium": 3720.00,
  "sum_assured": 500000.00,
  "age": 35,
  "gender": "MALE",
  "term_years": 20,
  "pricing_method": "BENEFIT_LEVEL",
  "benefit_premiums": [
    {
      "benefit_code": "DEATH_MAIN",
      "benefit_name": "Main Member Death",
      "member_role": "MAIN_MEMBER",
      "sum_assured": 500000.00,
      "rate": 0.52,
      "rate_basis": "PER_MILLE",
      "monthly_premium": 260.00,
      "pricing_method": "RATE_TABLE",
      "waiting_period_days": 180
    },
    {
      "benefit_code": "FUNERAL_EXP",
      "benefit_name": "Funeral Expenses",
      "member_role": "MAIN_MEMBER",
      "sum_assured": 15000.00,
      "rate": null,
      "rate_basis": "PER_MILLE",
      "monthly_premium": 50.00,
      "pricing_method": "FLAT",
      "waiting_period_days": 0
    }
  ]
}
Benefit-Level Pricing: Each benefit has its own pricing method.
RATE_TABLE: Looks up rate from rate_table_entries by age/gender. PER_MILLE: (SA / 1000) * rate
FLAT: monthly_premium = flat_premium (fixed amount per benefit)
Insured Lives: Each benefit targets a member_role; the matching life assured's age/gender is used for rate lookup.
POST
/api/quotes Save a quote to database
Request Body Schema
{
  "product_id": "uuid",
  "customer_id": "uuid",
  "age": 30,
  "gender": "MALE",
  "sum_assured": 500000,
  "monthly_premium": 310.00,          // from calculate response
  "term_years": 20,
  "benefit_premiums": [ ... ],         // from calculate response
  "insured_lives": [ ... ]             // from calculate request
}
GET
/api/quotes List all quotes
PUT
/api/quotes/{id}/accept Accept quote and create policy
Response
{
  "quote": {
    "id": "uuid",
    "quote_number": "QT-2026-000001",
    "status": "accepted",
    ...
  },
  "policy": {
    "id": "uuid",
    "policy_number": "PL-2026-000001",
    "effective_date": "2026-02-05",
    "expiry_date": "2046-02-05",
    "premium": 260.00,
    "coverage_amount": 500000.00,
    "status": "active"
  }
}

Policies

GET
/api/policies List all policies (with customer name and quote number)

Policy Servicing - Event Sourcing & Versioning

All policy changes are logged in an immutable event log with version snapshots for full audit trail.

GET
/api/policies/{policy_id}/events Query policy events with filtering
Query Parameters
?org_id=uuid
&category=LIFECYCLE|ENDORSEMENT|CLAIM|FINANCIAL  // optional filter
&event_type=POLICY_ISSUED|CLAIM_PAID|etc          // optional filter
&limit=50                                          // default 50
&offset=0                                          // for pagination
GET
/api/policies/{policy_id}/versions Get policy version history (snapshots)
Response
[{
  "version_number": 2,
  "snapshot_date": "2026-02-11T10:30:00Z",
  "change_reason": "Endorsement: CHANGE_COVER",
  "change_description": "Increased main member death benefit",
  "policy_snapshot": { /* full policy state at this version */ }
}]

Policy Servicing - Premium Management

GET
/api/policies/{policy_id}/premiums Get premium schedule (monthly billing dates)
Response
[{
  "id": "uuid",
  "due_date": "2026-03-05",
  "amount": 260.00,
  "status": "PENDING|PAID|OVERDUE|CANCELLED",
  "paid_date": "2026-03-03",
  "payment_reference": "PAY-2026-000123"
}]
POST
/api/policies/{policy_id}/premiums/{schedule_id}/pay Record a premium payment
Request Body
{
  "org_id": "uuid",
  "payment_date": "2026-03-03",
  "payment_reference": "PAY-2026-000123",
  "amount": 260.00
}
GET
/api/policies/{policy_id}/premium-summary Summary: total paid, outstanding, overdue counts
Response
{
  "monthly_premium": 260.00,
  "schedule_count": 12,
  "paid_count": 3,
  "overdue_count": 0,
  "total_paid": 780.00,
  "total_outstanding": 2340.00,
  "next_due_date": "2026-04-05",
  "next_due_amount": 260.00
}
GET
/api/policies/{policy_id}/transactions Finance ledger entries (premium due/received, adjustments)
POST
/api/policies/{policy_id}/premium-reconciliation/upload Bulk reconciliation upload from CSV data

Month-End Processing

Baseline month-end engine for overdue marking, annual premium indexation, and lapse-candidate evaluation.

POST
/api/month-end/process Run month-end process (supports dry-run mode)
Request Body
{
  "process_date": "2026-02-28",
  "dry_run": true,
  "mark_overdue": true,
  "apply_indexation": true,
  "evaluate_lapse_candidates": true,
  "auto_lapse": false,
  "limit_policies": 2000
}
POST
/api/month-end/config-preview Preview resolved escalation rates per product at process date

Policy Servicing - Endorsements

Modify active policies: change cover amounts, add/remove members.

POST
/api/policies/{policy_id}/endorse/preview Preview premium/cover impact before submitting endorsement
POST
/api/policies/{policy_id}/endorse Create policy endorsement
Request Body - CHANGE_COVER
{
  "org_id": "uuid",
  "endorsement_type": "CHANGE_COVER",
  "policy_benefit_id": "uuid",
  "new_sum_assured": 750000,
  "reason": "Customer requested increase"
}
Request Body - ADD_MEMBER
{
  "org_id": "uuid",
  "endorsement_type": "ADD_MEMBER",
  "member_role": "SPOUSE|CHILD|PARENT|EXTENDED",
  "first_name": "Jane",
  "last_name": "Doe",
  "date_of_birth": "1990-05-15",
  "gender": "FEMALE",
  "reason": "Adding spouse to policy"
}
Request Body - REMOVE_MEMBER
{
  "org_id": "uuid",
  "endorsement_type": "REMOVE_MEMBER",
  "policy_member_id": "uuid",
  "reason": "Child no longer dependent"
}

Policy Servicing - Lifecycle Management

Manage policy status: suspend, lapse, reinstate, cancel.

PUT
/api/policies/{policy_id}/suspend Suspend active policy (e.g. non-payment)
Request Body
{
  "org_id": "uuid",
  "reason": "Non-payment of premiums"
}
PUT
/api/policies/{policy_id}/lapse Lapse policy (grace period expired)
Request Body
{
  "org_id": "uuid",
  "reason": "Grace period expired, no payment received"
}
PUT
/api/policies/{policy_id}/reinstate Reinstate lapsed policy
Request Body
{
  "org_id": "uuid",
  "arrears_paid": true,
  "medical_clearance": true,
  "reason": "Arrears paid, medical clearance obtained"
}
PUT
/api/policies/{policy_id}/cancel Cancel policy permanently
Request Body
{
  "org_id": "uuid",
  "cancellation_type": "VOLUNTARY|LAPSE|NON_PAYMENT|FRAUD|OTHER",
  "reason": "Customer requested cancellation"
}

Policy Servicing - Claims Processing

Submit, assess, and pay claims with benefit-level validation and remaining cover tracking.

POST
/api/policies/{policy_id}/claims Submit claim with validation
Request Body
{
  "org_id": "uuid",
  "claim_date": "2026-02-10",
  "claim_type": "DEATH|DISABILITY|CRITICAL_ILLNESS|etc",
  "description": "Main member accidental death",
  "benefit_claims": [
    {
      "policy_benefit_id": "uuid",
      "claimed_amount": 500000
    }
  ]
}
Response
{
  "claim_id": "uuid",
  "claim_number": "CLM-2026-000042",
  "status": "SUBMITTED",
  "claim_date": "2026-02-10",
  "total_claimed": 500000.00,
  "benefit_items": [
    {
      "policy_benefit_id": "uuid",
      "benefit_name": "Death Benefit",
      "claimed_amount": 500000.00,
      "base_benefit_amount": 500000.00,
      "remaining_cover": 500000.00,
      "within_waiting_period": false
    }
  ]
}
PUT
/api/claims/{claim_id}/assess Assess claim (approve/reject per benefit)
Request Body
{
  "org_id": "uuid",
  "benefit_assessments": [
    {
      "claim_benefit_item_id": "uuid",
      "approved_amount": 450000,      // can be partial
      "decision_reason": "Approved with exclusions"
    },
    {
      "claim_benefit_item_id": "uuid",
      "approved_amount": 0,           // rejected
      "decision_reason": "Pre-existing condition"
    }
  ]
}
POST
/api/claims/{claim_id}/pay Pay claim and deduct from remaining cover
Request Body
{
  "org_id": "uuid",
  "payment_date": "2026-02-11",
  "payment_reference": "PAY-CLM-2026-000042",
  "benefit_payments": [
    {
      "claim_benefit_item_id": "uuid",
      "paid_amount": 450000
    }
  ]
}

// NOTE: This deducts paid_amount from policy_benefits.remaining_cover

Policy Servicing - Enhanced Detail View

GET
/api/policies/{policy_id}/detail Comprehensive policy view (one-stop for customer service)
Response
{
  "policy": { /* core policy fields */ },
  "product": { "id": "uuid", "name": "Funeral Family Plan" },
  "customer": { "id": "uuid", "first_name": "John", "last_name": "Doe", "email": "..." },
  "members": [
    {
      "id": "uuid",
      "role": "MAIN_MEMBER",
      "first_name": "John",
      "last_name": "Doe",
      "date_of_birth": "1980-01-01",
      "gender": "MALE",
      "effective_date": "2026-02-05",
      "is_active": true
    }
  ],
  "benefits": [
    {
      "id": "uuid",
      "benefit_name": "Main Member Death",
      "member_name": "John Doe",
      "sum_assured": 500000.00,
      "remaining_cover": 450000.00,
      "status": "ACTIVE",
      "waiting_period_days": 180,
      "waiting_period_end_date": "2026-08-04",
      "in_waiting_period": false
    }
  ],
  "premium_summary": { /* from /premium-summary endpoint */ },
  "recent_events": [ /* last 10 events */ ],
  "claims": [ /* all claims */ ],
  "current_version": 3
}

Product Configuration - Lapse Rules

Configure grace periods, payment reminders, and auto-reinstatement rules per product.

GET
/api/products/{product_id}/lapse-rules List all lapse rules for a product (ordered by effective_from DESC)
POST
/api/products/{product_id}/lapse-rules Create new lapse rule
Request Body
{
  "org_id": "uuid",
  "grace_period_days": 30,
  "grace_period_type": "CALENDAR",
  "reminder_schedule": [7, 3, 1],              // days before due date
  "auto_reinstate_if_paid_within_days": 14,
  "max_reinstatement_period_days": 180,
  "reinstatement_requires_medical_after_days": 90,
  "monthly_grace_days": 30,
  "quarterly_grace_days": 45,
  "annual_grace_days": 60,
  "send_sms_reminders": true,
  "send_email_reminders": true,
  "effective_from": "2026-01-01"
}
PUT
/api/lapse-rules/{rule_id} Update existing lapse rule

Dashboard

GET
/api/dashboard Get dashboard statistics
Response
{
  "products": 4,
  "active_products": 3,
  "customers": 2,
  "quotes": 1,
  "policies": 3,
  "active_policies": 3,
  "total_monthly_premium": 810.00,
  "total_cover": 1100000.00
}

Typical Workflows

🎯 New Business Flow

  1. Create Product: POST /api/products (or use wizard in Products tab)
  2. Launch Product: PUT /api/products/{id}/launch
  3. Create Customer: POST /api/customers
  4. Calculate Quote: POST /api/quotes/calculate
  5. Save Quote: POST /api/quotes
  6. Accept Quote: PUT /api/quotes/{id}/accept (creates policy + premium schedule + events)

💳 Premium Payment Flow

  1. Get Premium Schedule: GET /api/policies/{id}/premiums
  2. Record Payment: POST /api/policies/{id}/premiums/{schedule_id}/pay
  3. Check Summary: GET /api/policies/{id}/premium-summary
  4. Upload Reconciliation: POST /api/policies/{id}/premium-reconciliation/upload
  5. Review Finance Ledger: GET /api/policies/{id}/transactions

📝 Policy Endorsement Flow

  1. Change Cover: POST /api/policies/{id}/endorse (type: CHANGE_COVER)
  2. Add Member: POST /api/policies/{id}/endorse (type: ADD_MEMBER)
  3. Remove Member: POST /api/policies/{id}/endorse (type: REMOVE_MEMBER)
  4. Verify Event Logged: GET /api/policies/{id}/events?category=ENDORSEMENT

🏥 Claims Processing Flow

  1. Submit Claim: POST /api/policies/{id}/claims (validates waiting periods, caps at remaining cover)
  2. Assess Claim: PUT /api/claims/{id}/assess (approve/reject per benefit)
  3. Pay Claim: POST /api/claims/{id}/pay (deducts from remaining_cover)
  4. Verify Deduction: GET /api/policies/{id}/detail (check benefits.remaining_cover)

🔄 Lifecycle Management Flow

  1. Suspend: PUT /api/policies/{id}/suspend (e.g. non-payment)
  2. Lapse: PUT /api/policies/{id}/lapse (grace period expired)
  3. Reinstate: PUT /api/policies/{id}/reinstate (arrears paid + medical clearance)
  4. Cancel: PUT /api/policies/{id}/cancel (permanent cancellation)
  5. Audit Trail: GET /api/policies/{id}/versions (see all state changes)

🔍 Full Policy View

  • Single Endpoint: GET /api/policies/{id}/detail
  • Returns policy, product, customer, members, benefits (with waiting period flags), premium summary, recent events, claims, and current version — ideal for customer service dashboards.

Database Schema Explorer

Click on a table to view its structure and data. Lines show foreign key relationships.

Assumption Sets (Layer 6)