Underwriting Plugin

The Underwriting Plugin allows you to automatically add or remove underwriting flags to or from quotes or policy transactions.

The following API endpoints trigger the Underwriting Plugin:

If the Underwriting Plugin is triggered, but the plugin has not been implemented, the system will automatically allow quotes and policy transactions to proceed to the accepted stage of the policy lifecycle.

Underwriting Flags

The Underwriting Plugin can add or remove the following underwriting flags to or from quotes or policy transactions:

  • approve - The system will approve the quote or policy transaction and allow it to proceed to the next stage of the policy lifecycle, regardless of any other flags that have been added to it during the current execution of the Underwriting Plugin. Quotes and policy transactions cannot be approved if they have already been rejected as a result of a previous execution of the Underwriting Plugin.

  • block - The system will block the quote or policy transaction from proceeding to the next stage of the policy lifecycle.

  • decline - The system will block the quote or policy transaction from proceeding to the next stage of the policy lifecycle.

  • reject - The system will permanently block the quote or policy transaction from proceeding to the next stage of the policy lifecycle.

  • info - This flag can be used to provide underwriting information, but has no effect.

The block and decline flags both prevent quotes and policy transactions from proceeding to the next stage of the policy lifecycle until the flags have been removed or an approve flag is added. The block and decline flags function the same way, providing underwriters more flexibility to signal different types of denials.

If no flags have been added to a quote or policy transaction, the system will allow it to proceed to the accepted stage of the policy lifecycle.

Important

The reject flag permanently blocks a quote or policy transaction from proceeding to the next stage of the policy lifecycle. If this is not acceptable, we recommend using the decline or block flags as alternatives.

Implementation

Create a new Java class in the src/main/java/com/socotra/deployment/customer folder. All plugin code must be contained within this folder. We named our class UnderwritingPluginImpl.java in the example below, but you can name your class whatever you’d like.

Implement the UnderwritingPlugin interface, and override the method corresponding to your target entity type.

For example, the following class contains a method that approves commercial auto quotes:

public class UnderwritingPluginImpl implements UnderwritingPlugin {
    private static final Logger log = LoggerFactory.getLogger(UnderwritingPluginImpl.class);

    // Approves commercial auto quotes

    @Override
    public UnderwritingModification underwrite(CommercialAutoQuoteRequest commercialAutoQuoteRequest) {
        return UnderwritingModification.builder()
                .flagsToCreate(List.of(UnderwritingFlagCore.builder()
                        .level(UnderwritingLevel.approve)
                        .elementLocator(Optional.of(commercialAutoQuoteRequest.quote().locator()))
                        .tag(Optional.of("EXAMPLE_UNIQUE_IDENTIFIER"))
                        .note(Optional.of("This is an underwriting note."))
                        .build()))
                .build();
    }
}

The method argument contains the quote or policy to be underwritten. In the example above, the argument contains a commercial auto quote. Change the method argument class to CommercialAutoRequest to underwrite commercial auto policy transactions instead.

The method returns an UnderwritingModification object, which contains a list of UnderwritingFlagCore objects that will be added to the quote or policy transaction. Each UnderwritingFlagCore object contains the following fields:

  • level - The flag level

  • elementLocator - An optional element locator associated with the flag

  • tag - An optional unique identifier associated with the flag

  • note - An optional note associated with the flag

Checking for Existing Flags

Implementations must check for existing flags before adding new flags to avoid unintentionally adding previously cleared flags. The example below demonstrates the recommended approach to checking flags.

Example

The following example is based on the Prism configuration. Contact your Socotra representative for more information.

// Blocks commercial auto quotes and policy transactions based on driver experience and vehicle value

public class UnderwritingPluginImpl implements UnderwritingPlugin {
    private static final Logger log = LoggerFactory.getLogger(UnderwritingPluginImpl.class);

    @Override
    public UnderwritingModification underwrite(CommercialAutoQuoteRequest commercialAutoQuoteRequest) {
        return underwriteCommercialAuto(commercialAutoQuoteRequest.quote());
    }

    @Override
    public UnderwritingModification underwrite(CommercialAutoRequest commercialAutoRequest) {
        if (commercialAutoRequest.segment().isPresent()) {
            return underwriteCommercialAuto(commercialAutoRequest.segment().get());
        }

        return UnderwritingModification.builder().build();
    }

    private UnderwritingModification underwriteCommercialAuto(CommercialAuto commercialAuto) {
        // Check existing flags to avoid adding previously cleared flags

        DataFetcher dataFetcher = DataFetcher.getInstance();
        UnderwritingFlags flags = dataFetcher.getQuoteUnderwritingFlags(commercialAuto.locator());

        Set<String> existingRuleIds = new HashSet<>();

        existingRuleIds.addAll(flags.flags().stream()
                .map(flag -> flag.tag().orElse(""))
                .filter(tag -> !tag.isEmpty())
                .collect(Collectors.toSet()));

        existingRuleIds.addAll(flags.clearedFlags().stream()
                .map(flag -> flag.tag().orElse(""))
                .filter(tag -> !tag.isEmpty())
                .collect(Collectors.toSet()));

        List<UnderwritingFlagCore> newFlags = new ArrayList<>();

        // Evaluate driver experience

        for (Driver driver : commercialAuto.driverSchedule().drivers()) {
            if (driver.data().yearsOfExperience() < 5
                    && !existingRuleIds.contains("INEXPERIENCED_DRIVER" + driver.locator())) {
                newFlags.add(
                        createFlag(
                                UnderwritingLevel.block,
                                driver.locator(),
                                "INEXPERIENCED_DRIVER_" + driver.charges(),
                                "Driver has less than 5 years of experience."
                        )
                );
            }
        }

        // Evaluate vehicle value

        for (Vehicle vehicle : commercialAuto.vehicleSchedule().vehicles()) {
            if (vehicle.data().currentValue() != null
                    && vehicle.data().currentValue().compareTo(new BigDecimal("100000")) > 0
                    && !existingRuleIds.contains("HIGH_VALUE_VEHICLE")) {
                newFlags.add(
                        createFlag(
                                UnderwritingLevel.block,
                                vehicle.locator(),
                                "HIGH_VALUE_VEHICLE_" + vehicle.locator().toString(),
                                "Vehicle value exceeds underwriting guidelines."
                        )
                );
            }
        }

        // Add flags

        return UnderwritingModification.builder()
                .flagsToCreate(newFlags)
                .build();
    }

    private UnderwritingFlagCore createFlag(UnderwritingLevel level, ULID locator, String tag, String note) {
        return UnderwritingFlagCore.builder()
                .level(level)
                .elementLocator(Optional.of(locator))
                .tag(Optional.of(tag))
                .note(Optional.of(note))
                .build();
    }
}

Best Practices

  1. Always Check Existing Flags First

    • Use DataFetcher.getInstance().getQuoteUnderwritingFlags()

    • Check existing tag values to avoid unintentionally adding previously cleared flags

    • Make informed decisions about flag creation and updates

  2. Handle All Request Types

    • Implement both quote and policy transaction methods

    • Check for segment presence in policy transaction requests

  3. Use Unique Rule Identifiers

    • Set meaningful tag values for each flag type

    • Include element-specific identifiers when needed

  4. Provide Clear Flag Messages

    • Write actionable notes that help underwriters understand the issue

    • Include relevant context and next steps

  5. Test Thoroughly

    • Verify flag creation and duplicate prevention

    • Test both quote and policy transaction scenarios

    • Validate flag levels and their impact on policy progression

Next Steps

See Also