Socotra
Configuration GuidePlugins

Plugins Overview

Plugins are software components within the Socotra Insurance Suite that allow you to implement custom business logic written in Java and modify system processes such as underwriting, rating, and payment execution.

Once plugin implementations have been deployed, the system will automatically execute plugin code when entities move to a specific stage of their lifecycles, in response to system events, or when calling certain API endpoints. See the feature guide for each plugin for more information.

The following plugins are available in the Socotra Insurance Suite:

Implementation

Plugins are implemented as Java classes.

Implementations can be classified as either Global or Product implementations. Global implementations are located in the top-level configuration-name/plugins/java folder within the configuration folder structure, and Product implementations are located in product folders using the following folder structure: configuration-name/productName/plugins/java.

If both a Global and a Product implementation of a plugin are currently deployed, the system will only execute the Product implementation.

Automation Plugin implementations must be Global.

Once an implementation has been deployed, Global implementations will be moved to the src/main/java/com/socotra/deployment/customer folder, and Product implementations will be moved to a subfolder using the following folder structure: src/main/java/com/socotra/deployment/customer/productname. Implementations can be created and modified directly within these folder structures instead of the configuration folder structures.

To implement a plugin, create a Java class in one of the above folders, implement the interface for the plugin, and override the method specific to your target entity type.

For example, the following class implements the Validation Plugin and validates commercial accounts, commercial auto quotes, and commercial policy transactions:

// Validates commercial accounts, commercial auto quotes, and commercial policy transactions

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

    @Override
    public ValidationItem validate(CommercialAccountRequest commercialAccountRequest) {
        return ValidationItem.builder().build();
    }

    @Override
    public ValidationItem validate(CommercialAutoQuoteRequest commercialAutoQuoteRequest) {
        return ValidationItem.builder().build();
    }

    @Override
    public ValidationItem validate(CommercialAutoRequest commercialAutoRequest) {
        return ValidationItem.builder().build();
    }
}

The implementation defined above can only be deployed if two configuration objects are also deployed: An account configuration named CommercialAccount and a product configuration named CommercialAuto.

Execution

Once plugin implementations have been deployed, the system will automatically execute plugin code when entities move to a specific stage of their lifecycles, in response to system events, or when calling certain API endpoints. See the feature guide for each plugin for more information.

Certain plugins are triggered when quotes and policy transactions move to a specific lifecycle state:

StatePlugins
DraftN/A
ValidationPrecommit, Validation
PricingRating
UnderwritingUnderwriting
AcceptN/A
IssueN/A

Plugin Execution Context

The PluginExecutionContext class provides all plugins with a set of built-in methods for retrieving metadata related to the current plugin execution.

It can be used to access contextual information associated with the current plugin execution, such as the tenant locator or user locator.

The PluginExecutionContext class contains the following methods:

  • getRequestId()
  • getTenantLocator()
  • getBusinessAccount()
  • getUserLocator()
  • getUserRoles()

For example, the following code retrieves the requestId:

public class ValidationPluginImpl implements ValidationPlugin {

    @Override
    public ValidationItem validate(CommercialAutoQuoteRequest commercialAutoQuoteRequest) {
        PluginExecutionContext context = PluginExecutionContext.get();
        String requestId = context.getRequestId();

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

Data Fetcher

All plugins have access to the DataFetcher class, which can be used to retrieve data from a wide variety of entities, including quotes, policies, and accounts.

For example, the following code retrieves an account using an account locator:

// Retrieve an account using an account locator

@Override
public ValidationItem validate(CommercialAutoQuoteRequest commercialAutoQuoteRequest) {
    CommercialAccount account = DataFetcherFactory.get().getAccount(commercialAutoQuoteRequest.quote().accountLocator());

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

The following is a complete list of all methods available through the DataFetcher class:

MethodParametersResponse
getAccount()accountLocatorAccountResponse
getQuickQuote()quickQuoteLocatorQuickQuoteResponse
getQuote()quoteLocatorQuoteResponse
getQuoteUnderwritingFlags()quoteLocatorQuoteUnderwritingFlagsResponse
getQuotePricing()quoteLocatorQuotePriceResponse
getQuoteDocuments()quoteLocatorDocumentListResponse
getQuoteStaticData()locatorstatic
getTransaction()transactionLocatorPolicyTransactionResponse
getTransactionUnderwritingFlags()transactionLocatorTransactionUnderwritingFlagsResponse
getTransactionPricing()transactionLocatorTransactionPriceResponse
getDocumentsAttachedToTransaction()transactionLocatorDocumentListResponse
getAffectedTransactions()transactionLocatorAffectedTransaction[]
getPolicy()policyLocatorPolicyResponse
getPolicyStaticData()locatorstatic
getTerm()termLocatorTermResponse
getTermCharges()termLocatormap<transactionLocator, PolicyChargeResponse[]>
getTermSubsegmentSummaries()termLocatorStreamingEntity<SubsegmentSummary>, excluding documentSummary
getSegment()segmentLocatorSegmentResponse
getSegments() DeprecatedtransactionLocatorSegmentResponse[]
getSegmentByTransaction()transactionLocatorSegmentResponse
getSegmentDocuments()segmentLocatorDocumentListResponse
getAuxData()locator, keyAuxDataResponse
getAuxDataKeys()locator, offset, countAuxDataKeySetResponse
getUnderwritingFlag()underwritingFlagLocatorUnderwritingFlagResponse
getDiaries()referenceType, referenceLocator, offset, countDiaryEntryResponse[]
getPreferences()transactionLocatorPreferencesResponse
getInstallmentLattice()installmentLatticeLocatorInstallmentLatticeResponse
getInstallment()installmentLocatorInstallment
getInvoice()invoiceLocatorInvoiceResponse
getInvoiceDetails()invoiceLocatorInvoiceDetailsResponse
getPayment()paymentLocatorPaymentResponse
getDelinquencyEvents()delinquencyLocator, offset, countDelinquencyEventsResponse
getTask()taskLocatorTask
getUserAssociation()userAssociationLocatorUserAssociation
getFnol()fnolLocatorFnolResponse
getFnolLosses()fnolLocatorFnolLoss[]
getFnolClaims()fnolLocatorclaims
getContact()locatorContactRoles
getQuoteContacts()quoteLocatorContactRoles[]
getPolicyContacts()policyLocatorContactRoles[]
getAccountContacts()accountLocatorContactRoles[]
getFnolContacts()fnolLocatorContactRoles[]

Resource Selector

All plugins have access to the ResourceSelector class, which can be used to retrieve data from resources such as tables and secrets.

The ResourceSelector automatically selects resource instances based on resource selection rules. See the Versioned Resource Selection feature guide for more information.

Data Tables

The ResourceSelector can be used to retrieve data from data tables.

Here's an example of retrieving a record from a data table named VehicleTypeFactor:

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

    // Retrieve a record from the VehicleTypeFactor table

    @Override
    public RatingSet rate(CommercialAutoQuoteRequest commercialAutoQuoteRequest) {
        CommercialAutoQuote commercialAutoQuote = commercialAutoQuoteRequest.quote();
        List<RatingItem> ratingItems = new ArrayList<>();

        Vehicle vehicle = commercialAutoQuote.vehicleSchedule().vehicles().stream().findFirst().orElseThrow();

        Optional<VehicleTypeFactor> record = ResourceSelectorFactory.getInstance()
                .getSelector(commercialAutoQuote)
                .getTable(VehicleTypeFactor.class)
                .getRecord(VehicleTypeFactor.makeKey(vehicle.data().vehicleMake(), vehicle.data().vehicleModel(), vehicle.data().vehicleYear()));

        BigDecimal rate = record.orElseThrow().rate();

        ratingItems.add(RatingItem.builder()
                .elementLocator(vehicle.locator())
                .chargeType(ChargeType.premium)
                .rate(rate)
                .build());

        return RatingSet.builder().ok(true).ratingItems(ratingItems).build();
    }
}

Here's an example of the VehicleTypeFactor data table:

makeSymbolmodelSymbolmodelYeartypeFactorcollFactor
keykeykeyvaluevalue
ToyotaCamry20230.842210.86764
FordExplorer20220.878390.91023

In the previous code example, a CommercialAutoQuote functions as the reference point for resource selection logic. However, you can also specify a time as the reference point instead.

For example:

Optional<VehicleTypeFactor> record = ResourceSelectorFactory.getInstance()
        .getSelector(Instant.now())
        .getTable(VehicleTypeFactor.class)
        .getRecord(VehicleTypeFactor.makeKey(vehicle.data().vehicleMake(), vehicle.data().vehicleModel(), vehicle.data().vehicleYear()));

Range Tables

The ResourceSelector can be used to retrieve data from range tables.

Here's an example of retrieving a record from a range table named AdjustedRate:

Optional<AdjustedRate> record = ResourceSelectorFactory.getInstance()
        .getSelector(commercialAutoQuote)
        .getRangeTable(AdjustedRate.class)
        .getRecord(AdjustedRate.makeKey(), BigDecimal.TEN);

Here's an example of range table extrapolation:

ResourceSelectorFactory.getInstance()
        .getSelector(commercialAutoQuote)
        .getRangeTable(VehicleStateFactor.class)
        .extrapolate(TableUtils.makeKey("Toyota", "California"), BigDecimal.valueOf(2016),
                VehicleStateFactor::factor, Interpolation.linear)
        .ifPresent(factor -> log.info("Extrapolated VehicleStateFactor for year {}: {}", 2016, factor));

Here's an example of range table interpolation:

ResourceSelectorFactory.getInstance()
        .getSelector(commercialAutoQuote)
        .getRangeTable(VehicleStateFactor.class)
        .interpolate(TableUtils.makeKey("Toyota", "California"), BigDecimal.valueOf(2016),
                VehicleStateFactor::factor, Interpolation.linear)
        .ifPresent(factor -> log.info("Interpolated VehicleStateFactor for year {}: {}", 2016, factor));

Here's an example of retrieving the range table record for a key and range selection start that is closest to but not greater than the specified value:

ResourceSelectorFactory.getInstance()
        .getSelector(commercialAutoQuote)
        .getRangeTable(VehicleStateFactor.class)
        .getLowerAdjacentRecord("exampleKey".getBytes(), BigDecimal.valueOf(108))
        .ifPresent(record -> log.info("Lower adjacent record: {}", record));

If multiple ranges match, the range with the lowest range selection end is returned.

Here's an example of retrieving the range table record for a key and range selection start that is closest to but not less than the specified value.

ResourceSelectorFactory.getInstance()
        .getSelector(commercialAutoQuote)
        .getRangeTable(VehicleStateFactor.class)
        .getUpperAdjacentRecord("exampleKey".getBytes(), BigDecimal.valueOf(108))
        .ifPresent(record -> log.info("Upper adjacent record: {}", record));

If multiple ranges match, the range with the lowest range selection end is returned.

Constraints

The ResourceSelector can be used to retrieve constraints.

For example:

ConstraintsFetcher constraintsFetcher = ResourceSelectorFactory.getInstance()
        .getSelector(commercialAutoQuote)
        .getConstraints(ClassCodes.class);

Collection<String> constraints = constraintsFetcher.get("exampleKey".getBytes());

Secrets

Lastly, the ResourceSelector can be used to retrieve secrets by referencing the staticName of the secret.

Here's an example of a SecretRef configuration object named ExternalService:

{
	"items": {
		"url": {
			"dataType": "string"
		},
		"apiToken": {
			"dataType": "string"
		},
		"timeOutSeconds": {
			"dataType": "int"
		}
	}
}

Execute the deployConfigToTenant Gradle task to deploy your configuration.

Once these configurations have been deployed, create your secret using the Create a Secret API endpoint.

For example:

{
	"name": "ExampleSecret",
	"staticName": "ExternalService",
	"secret": {
		"url": "https://example.url.com",
		"apiToken": "Bearer EXAMPLE_TOKEN",
		"timeOutSeconds": 1000
	}
}

Secrets must be added to at least one resource group before they can be accessed through the AutomationPluginContextData class by using the Create a Resource Group or Update a Resource Group API endpoint.

Here's an example request for the Create a Resource Group API endpoint:

{
	"name": "ExampleResourceGroup",
	"selectionStartTime": "2023-12-22T19:09:27+0000",
	"resourceNames": ["ExampleSecret"]
}

Here's an example request for the Update a Resource Group API endpoint:

{
	"name": "ExampleResourceGroup",
	"selectionStartTime": "2023-12-22T19:09:27+0000",
	"addResources": ["ExampleSecret"]
}

Once the secret has been added to a resource group, execute the refreshReferenceDatamodel Gradle task to generate the Java class containing your secrets.

Secret fields can now be accessed through the ResourceSelector.

For example:

Optional<ExternalService> secret = ResourceSelectorFactory.getInstance()
        .getSelector(commercialAutoQuote)
        .getSecret(ExternalService.class);

String url = secret.url();
String apiToken = secret.apiToken();
Integer timeOutSeconds = secret.timeOutSeconds();

See the Versioned Resource Selection feature guide for more information on resource selection logic.

Aux Data

Aux data refers to general-purpose key-value pairs stored within the Socotra Insurance Suite. All plugins have access to aux data via the Data Fetcher.

The following aux data methods are available to all plugins via the Data Fetcher:

  • getAuxDataKeys()
  • getAuxData()
  • setAuxData()
  • deleteAuxData()

Here's a demonstration of each aux data method:

@Override
public ValidationItem validate(CommercialAutoQuoteRequest commercialAutoQuoteRequest) {
    String quoteLocator = commercialAutoQuoteRequest.quote().locator().toString();

    // Parameters: getAuxDataKeys(locator, offsetValue, pageSize)
    AuxDataKeysSet keySet = DataFetcher.getInstance().getAuxDataKeys(quoteLocator, 0, 100);

    if (!keySet.auxDataKeys().isEmpty()) {
        String key = keySet.auxDataKeys().stream().findFirst().get().key();
        String value = DataFetcher.getInstance().getAuxData(quoteLocator, key).value();

        Collection<AuxDataSet> auxDataSets = new ArrayList<>();

        AuxDataSet createRequest = AuxDataSet.builder().key(key).value(value).build();

        auxDataSets.add(createRequest);

        createRequest = AuxDataSet.builder().uiType(UiType.normal).key("keyToDelete").value(value).build();

        auxDataSets.add(createRequest);

        AuxDataSetCreateRequest setCreateRequest = AuxDataSetCreateRequest.builder()
                .auxDataSettingsName("ShortExpire")
                .auxData(auxDataSets).build();

        AuxDataService.getInstance().setAuxData(quoteLocator, setCreateRequest);
        AuxDataService.getInstance().deleteAuxData(quoteLocator, "keyToDelete");
    }

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

Events Service

The EventsService can be used to manually trigger custom events within Socotra, allowing you to execute workflows via webhooks or an event-driven implementation of the Automation Plugin.

For example:

// Execute a custom event named ExampleEvent with payload data
EventsService.getInstance().createEvent(CustomEvent.ExampleEvent, Map.of("quote", quote.locator(), "info", "Plugin executed"));

// Execute a custom event named ExampleEvent without payload data
EventsService.getInstance().createEvent(CustomEvent.ExampleEvent);

Money Service

The MoneyService can be used to perform precise financial calculations based on a specified currency code.

Here's a demonstration of MoneyService functionality:

// Create a MoneyService object for a specific currency such as US dollars
MoneyService moneyService = new MoneyService("USD");

BigDecimal amount = new BigDecimal("123.4567");

// Round the amount to the currency's default number of decimal places
BigDecimal roundedAmount = moneyService.toMoney(amount); // Result: 123.46

// Example of a rate calculation
BigDecimal totalAmount = new BigDecimal("1000.00");
BigDecimal duration = new BigDecimal("12.0");

// Calculate a rate for a target amount over a duration
BigDecimal rate = moneyService.getRateForTargetAmount(totalAmount, duration);

External API Calls

All plugins can call external API endpoints via the Java HttpClient.

For example:

try (HttpClient client = HttpClient.newHttpClient()) {
    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://example.com/some-data"))
            .GET()
            .build();

    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

    log.info("Response: {}", response.toString());

} catch (Exception e) {
    log.error("Exception: {}", e.toString());
}

The Java HttpClient is the only HTTP client currently supported by the platform. The Automation Plugin is the only plugin that can call Socotra API endpoints directly.

Logging

The Logging API can be used to view the history of plugin executions and Java logging messages.

First, retrieve a list of plugin executions using the Fetch a List of Logs API endpoint. Optional query parameters can be used to narrow down this list.

For example, use the createdAtMin query parameter to view plugin executions that occurred after a specified timestamp:

createdAtMin=2026-07-25T22:00:00.000Z

Next, retrieve Java logging messages for a plugin execution by calling the Fetch Logs for a Request API endpoint and specifying the target PluginLogsMetadata locator as the locator for the request.

Plugin Restrictions

The following restrictions apply to all classes that implement a Socotra plugin interface:

  • Classes cannot be declared abstract and must be instantiable.
  • Classes cannot have a constructor with one or more arguments. A no-argument constructor is allowed and will be generated automatically if not provided.

The system will block the deployment of plugin classes that violate these rules.

Each plugin is executed in an isolated memory space. Accessing plugin fields or calling methods belonging to a different plugin is not supported and should not be attempted.

Next Steps

See Also

On this page