Skip to content

HyperExponential (Hx) Integration

HyperExponential (Hx) is an actuarial pricing platform. Workbench integrates with it so that underwriters can price risks in Hx while Workbench remains the system of record. The underwriter never leaves Workbench to trigger or complete the pricing cycle — Hx is accessed via an embedded link and the pricing data flows back automatically.


How it works

The integration is built around a pull/push model:

  1. When a quote action is triggered in Workbench, the Rating Service creates a policy in Hx via the Hx API.
  2. Hx pulls risk data from Workbench via a GET endpoint.
  3. The underwriter prices the risk in the Hx UI.
  4. Hx pushes the pricing results back to Workbench via a POST endpoint.
  5. The underwriter completes the quote in Workbench, which finalises the Hx policy.

The same core flow applies to new business, renewals, and MTAs — with some differences at step 1 and 2 depending on transaction type (covered below).


New business flow

1. Underwriter triggers Quote action in Workbench
2. Rating Service creates a new policy in Hx
   POST {hxApiUrl}/policies
   → Hx returns: policyId, policyOptionId, policyOptionURL (renew_url)
3. Underwriter clicks through to Hx via the policyOptionURL
4. Hx pulls risk data from Workbench
   GET https://api.{client-env}.sendworkbench.com/policies/hx/mapped/{policyGroupId}/structured-quote
5. Underwriter reviews data and prices the risk in Hx
6. Hx pushes pricing results back to Workbench
   POST https://api.{client-env}.sendworkbench.com/policies/hx/mapped/{policyGroupId}/structured-quote
7. Underwriter triggers "Complete Quote" action in Workbench
   → Rating Service calls POST {hxApiUrl}/complete-quote
   → Hx policy status moves to FINAL
8. Pricing data (technical price, achieved price, machine price) is written to the risk record

What Workbench sends to Hx on policy creation

When Workbench creates the Hx policy (step 2), it sends:

Field Source
name Insured party name from the risk
role From hxPricingConfig.role (e.g. "underwriter")
team Derived from business class via teamsProviderConfig
live From hxPricingConfig.policyCreatedAsLive (default: false)
customerId Workbench policy group ID (if sendCustomerId: true)
pasReferences Workbench policy group ID — used to link Hx and Workbench together
modelVersionId Selected based on pricingStrategy config
description Policy description
tags Risk type + WORK_IN_PROGRESS
initialOption.name Policy option name
initialOption.inceptionDate / expiryDate Risk dates, formatted as yyyy-MM-dd

Renewal flow

The renewal flow differs from new business at the policy creation step. Instead of creating a fresh policy, Workbench clones the expiring Hx policy.

1. Renewal risk created in Workbench (manually or via renewal action)
2. Rating Service clones the expiring Hx policy
   POST {hxApiUrl}/policies/{expiringPolicyId}/renew
   → Returns new policyId, policyOptionId, policyOptionURL
3. If importExpiringPolicyData: true (default):
   Hx imports expiring policy data automatically
   POST {hxApiUrl}/policy-option-instances/{policyOptionId}/import-expiring-policy-data
   → Prefills the Hx model with last year's data
4–8. Same pull/push cycle as new business

Key renewal configuration decisions

importExpiringPolicyData (default: true) — controls whether Hx automatically prefills the renewal with the expiring policy's data. This is almost always what you want. Set to false only if the expiring Hx model is incompatible with the renewal model (e.g. the model structure changed significantly between years).

shouldSetExpiringPolicyReferenceOnRenewals (default: false) — sets the expiringPolicyNumber field on the Hx renewal policy. Enable if the Hx model uses this field for continuity calculations (e.g. prior year premium comparisons).

pricingStrategy — controls which model version is used for the renewal:

Value Behaviour
INCEPTION_DATE Uses the Hx model version that was live on the risk's inception date. Recommended for most clients — ensures the renewal uses the same model generation that was in use when the risk was originally written
FIRST_QUOTE Locks to the model version used on the very first quote for the risk, regardless of model updates

The pull/push data model

This is what Hx receives when it pulls data from Workbench, and what it sends back after pricing.

Pull (GET) — what Hx reads from Workbench

GET https://api.{client-env}.sendworkbench.com/policies/hx/mapped/{policyGroupId}/structured-quote

Top-level fields:

Field Description
sendPolicyId Workbench policy group ID
riskId Workbench risk ID
transactionType NEW, RENEWAL, or MTA
stage Current Workbench risk stage (e.g. QUOTE, WORK_IN_PROGRESS)
currency Risk currency
inceptionDate / expiryDate Policy period
insuredName Name of the insured
insuredDomicile Insured's country/domicile
insuredAddress / insuredPostcode Insured address fields
brokerName Broker party name
businessClassName Business class name (e.g. "Property")
businessClassTypeCode Business class code (e.g. "PR")
underwriterExternalId Underwriter's external user ID
quotingUserExternalId Quoting user's external ID
customerProfessionCode Customer profession code from the risk
initialPricing Whether this is the first pricing pass
readOnly Whether the pricing session is read-only
products List of active products on the risk
productTypeLegend Code → display name mapping for products
attributeTypeLegend Code → display name mapping for asset attribute types
customerExtension Optional client-specific extension object

Layers (layers[]):

Each layer maps to a policy in Workbench terms.

Field Description
id Workbench layer/policy ID
layerName Layer name
exportId Optional export reference
policyType PRIMARY, LOSS_LIMIT, XOL, or TIV
technicalPrice Sum of active section technical prices
achievedPrice Sum of active section achieved prices
machinePrice Sum of active section machine prices
netRenewalPremium Net renewal premium (renewals)
netAdjustedExpiringPremium Net adjusted expiring premium (renewals)
commission Commission rate (as decimal, e.g. 0.05 = 5%)
signedLine Signed line percentage
attachment Attachment point
limitOfIndemnity Limit of indemnity
quotedDate Date the layer was quoted
assetAllocation Asset IDs applicable to this layer (null = all assets, [] = no assets)

Sections (layers[].sections[]):

Each section maps to a product_cover in Workbench.

Field Description
id Workbench product cover ID
productCode Product code (e.g. "PD", "BI")
subType Sub-class 1 code
subType2 Sub-class 2 / contract type code
status ACTIVE, INACTIVE, or DELETED
technicalPrice Section-level technical price
achievedPrice Section-level achieved price
machinePrice Section-level machine price
retentions[] Retention entries: retentionTypeCode, retentionValue, rowStatus
limits[] Limit entries: limitTypeCode, limitValue, rowStatus
currency Section currency (if multi-currency)
exchangeRateToBaseCurrency Exchange rate if applicable
signedLine Section-level signed line
section Section reference

Assets (assets[]):

Field Description
id Workbench asset ID
organisationName Asset organisation name
address / postcode / country Asset location
attributes[] Coverage values: attributeTypeCode, value, originalValue, name
conflictOnOutOfSequenceMTA Whether this asset has an MTA conflict

Push (POST) — what Hx sends back to Workbench

POST https://api.{client-env}.sendworkbench.com/policies/hx/mapped/{policyGroupId}/structured-quote

The push payload wraps the (modified) pull payload in a summary envelope:

{
  "quoteExportId": "111",
  "machinePrice": 251.0,
  "technicalPrice": 250.0,
  "achievedPrice": 252.0,
  "netRenewalPremium": 0,
  "netAdjustedExpiringPremium": 0,
  "payload": { <<same structure as GET, with pricing populated>> },
  "pricingEngineSpecificData": {}
}

Summary envelope fields:

Field Description
quoteExportId Optional ID allocated within Hx
achievedPrice Overall achieved price — must equal the sum of active layer achieved prices
technicalPrice Overall technical price — must equal the sum of active layer technical prices
machinePrice Overall machine price — must equal the sum of active layer machine prices
netRenewalPremium Net renewal premium at the option level
netAdjustedExpiringPremium Net adjusted expiring premium at the option level
payload The GET structure, augmented with Hx-calculated pricing values
pricingEngineSpecificData Used to pass back updated Hx/Workbench policy ID mappings if they changed in Hx (e.g. if the user worked on a different policy option than the one Workbench originally created)

What Hx populates on the push: - technicalPrice, achievedPrice, machinePrice at both layer and section level - retentions and limits — Hx may modify these values - currency — can be updated via the push - customerProfessionCode — can be updated via the push - inceptionDate / expiryDate — editable on new business and renewals, but not on MTAs

Warning

Prices at layer level must always equal the sum of prices across active sections on that layer. Similarly, prices in the top-level envelope must equal the sum across active layers. Hx is responsible for populating these correctly — but if the Hx model doesn't do this, Workbench will store inconsistent premium values.


be_config.json configuration

All Hx configuration lives in hxPricingConfig in be_config.json.

Minimum required configuration

{
  "hxPricingConfig": {
    "authScheme": "AZURE_AD",
    "authenticationURL": "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token",
    "grantType": "client_credentials",
    "clientId": "${HX_CLIENT_ID}",
    "clientSecret": "${HX_CLIENT_SECRET}",
    "scope": "api://{hx-app-id}/.default",
    "apiURL": "https://api.hyperexponential.com",
    "role": "underwriter",
    "pricingStrategy": "INCEPTION_DATE",
    "onlyAllowPublishedModels": true
  }
}

Warning

Credentials must be injected via environment variables or AWS Secrets Manager. Never commit them as plain text.

Authentication options

Azure AD (most common):

{
  "authScheme": "AZURE_AD",
  "authenticationURL": "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token",
  "grantType": "client_credentials",
  "clientId": "${HX_CLIENT_ID}",
  "clientSecret": "${HX_CLIENT_SECRET}",
  "scope": "api://{hx-app-id}/.default"
}

Auth0:

{
  "authScheme": "AUTH0",
  "authenticationURL": "https://{your-domain}.auth0.com/oauth/token",
  "clientId": "${HX_CLIENT_ID}",
  "clientSecret": "${HX_CLIENT_SECRET}",
  "audience": "https://api.hyperexponential.com",
  "userName": "${HX_USERNAME}",
  "password": "${HX_PASSWORD}"
}

Confirm the scheme with your Hx account team — the scheme configured here must match what the Hx tenant is set up to accept.

Full configuration reference

Field Default Description
apiURL Base URL for the Hx API
role The Hx role under which policies are created (e.g. "underwriter")
policyCreatedAsLive false If true, policies are created as live immediately. Keep false — policies should only go live at bind
sendCustomerId true Sends the Workbench policy group ID to Hx as customerId. Keep true
pricingStrategy INCEPTION_DATE Model version selection strategy — see Renewal flow
onlyAllowPublishedModels true Prevents rating against unpublished/draft Hx models. Set false in Dev only
onlyAllowTestableModelVersions false Restricts to testable model versions only. Leave false unless specifically required
forceQuotesOnSameModelToUseSameModelVersion false Forces all quote options on a risk to use the same Hx model version. Enable when multi-option is active and consistency is required
importExpiringPolicyData true Auto-imports expiring policy data into Hx on renewal. Recommended: true
shouldSetExpiringPolicyReferenceOnRenewals false Populates the expiring policy reference in Hx on renewals. Enable if the Hx model uses this field
shouldReuseExpiringPolicyReferenceOnCopiedPolicies false Reuses expiring policy reference on copied (not renewed) risks
priceSynchronizationEnforced false Blocks quote completion if AP and TP are not in sync between Hx and Workbench
additionalPricingDetailRequired false Requires additional customer data before the rating action is available
setRaterStatusOnUpdate true Updates the rater status field on the risk when Hx sends data back
validationErrorIgnoredOnStatusUpdate false Suppresses Hx validation errors during status updates. Only enable if advised by Send
enableMultiOption false Enables multi-option quoting — multiple Hx policy options per risk
connectionTimeoutInSeconds 15 HTTP connection timeout for Hx API calls
readTimeoutInSeconds 15 HTTP read timeout for Hx API calls
hxSessionTimeoutInSeconds 15 How long an Hx browser session is considered active
statusUpdateThreadPoolSize 20 Thread pool size for Hx status sync. Increase for high-volume environments (e.g. DUA)
statusUpdateTimeoutInSeconds 120 Maximum wait time for a status update response from Hx

Teams configuration

teamsProviderConfig controls which Hx team newly created policies are assigned to. Set to null if team assignment is not needed.

Assign all policies to a single team:

{
  "teamsProviderConfig": {
    "type": "LITERAL",
    "teamLiteral": "Underwriting Team"
  }
}

Prefix team name with business class (e.g. "UW-Marine", "UW-Property"):

{
  "teamsProviderConfig": {
    "type": "BUSINESS_CLASS_AND_LITERAL",
    "teamLiteral": "UW-"
  }
}

Explicit business class → team mapping:

{
  "teamsProviderConfig": {
    "type": "BUSINESS_CLASS_NAME_MAP",
    "businessClassNameToTeamMap": {
      "Marine Cargo": "Marine Team",
      "Property": "Property & Casualty",
      "Liability": "Property & Casualty"
    }
  }
}

If a business class has no entry in the map, the business class name itself is used as the team name.

Product cover matching strategy

productCoverMatchingStrategy controls how Workbench matches sections in the Hx push response back to product covers in its own data model.

Value When to use
PRICING_ENGINE_ID Default and most common. Matches sections using their Hx section ID and pricing engine ID. Each section must have at least one of id or pricingEngineId
PRODUCT_HIERARCHY Matches using the combination of productCode, subType, and subType2. Use when Hx model sections map directly to Workbench product hierarchy nodes and the combination of these three values is unique per section

Async tasks

Some Hx operations are asynchronous. There are two triggering strategies:

Legacy strategy — tasks defined as a list, fired after policy creation:

{
  "useNewHxAsyncTaskTriggering": false,
  "postPolicyCreationAsyncTask": ["my_async_task"],
  "asyncStatusUpdateEnabled": false,
  "updatePoliciesStatusesTaskName": "workbench_sync_status",
  "asyncTaskPollerMaxAttempts": 3,
  "asyncTaskPollerBackOffPeriod": 2000
}

New strategy — tasks mapped to named lifecycle trigger points (recommended for new implementations):

{
  "useNewHxAsyncTaskTriggering": true,
  "asyncTaskTriggerPoints": {
    "policyCreation": "hx_policy_created",
    "quoteCompletion": "hx_quote_completed",
    "brokerResponseCompletion": "hx_broker_response_completed"
  },
  "asyncTaskPollerMaxAttempts": 3,
  "asyncTaskPollerBackOffPeriod": 2000
}

With the new strategy, Hx handles all internal task orchestration — you only configure one trigger name per lifecycle step. Post-creation async tasks are fire-and-forget: if the task fails to start, the error is surfaced; if the task itself fails internally, it won't be reported back to the user.


Pricing screen configuration

The Hx pricing screen in Workbench is configured via screen metadata files in the client config repository:

config/{client}/screen-meta-data/config/default/structured_policies_hx_pricing.json

This file defines which placing types and risk types use the Hx pricing screen:

[
  {
    "placingType": "OPEN_MARKET",
    "riskType": "NEW",
    "operationName": "structured_policies_hx_pricing",
    "dataFile": "structured-policies-hx-pricing-meta-data.json"
  },
  {
    "placingType": "OPEN_MARKET",
    "riskType": "RENEWAL",
    "operationName": "structured_policies_hx_pricing",
    "dataFile": "structured-policies-hx-pricing-meta-data.json"
  },
  {
    "placingType": "OPEN_MARKET",
    "riskType": "MTA",
    "operationName": "structured_policies_hx_pricing",
    "dataFile": "structured-policies-hx-pricing-meta-data.json"
  }
]

The dataFile defines the layout and field definitions for the pricing panel. The reference implementation is at:

config/senduk/screen-meta-data/files/default/structured-policies-hx-pricing-meta-data.json

The screen is split into four groups:

Group Purpose
policyGroup Quote name, description, rater status
policy Layer-level details: dates, currency, commission rate
productCoverSummary Section mapping: line of business, product, subType, contract type
productCoverDetail Premium fields: technical price, achieved price, stamps, retentions, limits

Common issues

Quote is blocked from completing Check priceSynchronizationEnforced — if true, the achieved price and technical price must match between Hx and Workbench before completion is allowed. The underwriter must reconcile any discrepancy in Hx first.

Renewal data not prefilling in Hx Check importExpiringPolicyData — should be true. Also verify that the expiring Hx policy ID has been stored on the previous risk in Workbench (identifiers: HX_POLICY_ID, HX_POLICY_OPTION_ID). If the expiring policy was priced in a structurally different Hx model, set importExpiringPolicyData: false to avoid import errors.

Validation error blocking finalisation The underwriter needs to resolve the validation errors within the Hx UI. The error message will reference the specific Hx policy option ID. Only enable validationErrorIgnoredOnStatusUpdate: true as a last resort and with Send's guidance.

Session conflict error Hx prevents concurrent edits. If the user has the policy open in Hx in another browser tab or session, they must close it before completing actions in Workbench.

Prices not writing back correctly Verify that layer-level prices equal the sum of section prices, and that the top-level envelope prices equal the sum across layers. This is Hx's responsibility on the push — if the Hx model is calculating summations incorrectly, it needs to be fixed in Hx.

Wrong model version being used Review pricingStrategy and confirm the correct inception date is set on the risk. For renewals, INCEPTION_DATE should use the renewal's inception date (not the expiring policy's). If forceQuotesOnSameModelToUseSameModelVersion is enabled, all options will lock to the first model version found — check that the first quote option was priced against the intended version.


See also