How to use Benefit Calculator with Package Search API
Endpoint: POST /product/compare/benefit-analysis
This guide explains how to call the Benefit Calculator API, build valid request payloads, and interpret the response. Use it together with the IMG Comparator API OpenAPI spec for full schema details.
1. What is the Benefit Calculator?
The Benefit Calculator takes a customer’s current (previous) health fund policy and actual annual usage of extras services, then compares that against other packages in the IMG system.
It returns:
- Claimable benefits — How much the customer can claim from each policy for their usage.
- Net benefit — Benefits received minus premiums (can be negative).
- Switch & Save — Yearly (or weekly/fortnightly/monthly) savings if they move from their current policy to each suggested one.
So agents can recommend policies based on real usage and out-of-pocket costs, not only on headline limits.
2. Prerequisites
You can only get benefit calculator results when all of the following are true:
| Requirement | Details |
|---|---|
| Previous fund | The customer must have a previous fund. |
| Extras coverage | The customer cannot be on hospital-only. |
| Membership type | application.policy.membership_type must match benefit_analysis_data.previous_fund.membership_type. |
| Usage data | You must send at least one participant with at least one benefit (service usage) in benefit_analysis_data.participants. |
| Corporate access | The corporate must have benefit calculator API access enabled. |
3. Request overview
The request body is the same shape as the standard package search, with two differences:
- Filters:
filters.apply_benefit_analysismust betrue. - Root-level object:
benefit_analysis_datais required and must contain participants, state, cover_type, membership_type, and previous_fund.
Top-level fields:
| Field | Required | Description |
|---|---|---|
application | Yes | Same as package search: personal, primary_address, policy; optional partner. |
filters | Yes | Same as package search; must include "apply_benefit_analysis": true. |
services | Yes | hospital (array of service IDs), ancillary (array of service IDs). From /product/services. |
benefit_analysis_data | Yes | See section 4. |
application.personal.previous_fund must be populated (has_previous_fund, fund_id, fund_name, hospital_product and/or ancillary_product, membership) so the backend knows the current policy. Product IDs there should match the IDs you put in benefit_analysis_data.previous_fund.
4. benefit_analysis_data
This object drives the benefit calculation. All of these are required at the root of benefit_analysis_data:
| Field | Type | Required | Description |
|---|---|---|---|
participants | array | Yes | At least one participant; see participant rules below. |
state | string | Yes | Australian state code (e.g. "VIC"). Must match application.primary_address.state. |
cover_type | integer | Yes | 0 = Hospital, 1 = Extras, 2 = Combined. Cannot be 0 (hospital-only). |
membership_type | integer | Yes | 0 = Single, 1 = Couple, 2 = Family, 3 = Single Parent, etc. Must match application.policy.membership_type and previous_fund.membership_type. |
previous_fund | object | Yes | Current policy identifiers; see below. |
4.1 previous_fund
Describes the customer’s current policy so the engine can compare it to alternatives.
Required for all:
| Field | Type | Description |
|---|---|---|
membership_type | integer | Same as above (0/1/2/3). |
fund_name | string | e.g. "BUPA", "NIB Health Funds Ltd.". |
product_type | integer | 0 = Hospital, 1 = Extras, 2 = Combined. |
product_name | string | Product name (e.g. combined product name or hospital product name). |
hospital_product_id | integer | Required. Price ID from /product/ (Product Search). For combined products this is the single combined price ID. For separate hospital + extras, this is the hospital price ID. |
Required only for synthetic (separate hospital + extras) policies:
| Field | Type | Description |
|---|---|---|
ancillary_product_id | integer | Extras product price ID from /product/. Omit for combined products. |
Example — combined product (single product for hospital + extras):
"previous_fund": {
"membership_type": 0,
"fund_name": "BUPA",
"product_type": 2,
"product_name": "Gold Ultimate Health Cover",
"hospital_product_id": 6529563
}
Example — synthetic (separate hospital and extras):
"previous_fund": {
"membership_type": 2,
"fund_name": "ACA Health Benefits Fund",
"product_type": 0,
"product_name": "Bronze Essentials Hospital 750",
"hospital_product_id": 6435350,
"ancillary_product_id": 6435563
}
Get these IDs from the Product Search API (/product/) using fund, membership, state, policy type, and product name.
4.2 participants
Participants are the people on the policy whose extras usage you are modelling. Rules:
- Exactly one
primary. - At most one
partner. - Up to five dependants:
dependent_1…dependent_5.
If you send more than 1 primary, or more than 1 partner, or more than 5 dependants, the API returns 400: "Maximum 1 primary, 1 partner, and 5 dependants allowed".
Each participant has:
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | One of: primary, partner, dependent_1, dependent_2, dependent_3, dependent_4, dependent_5. |
benefits | array | Yes | At least one benefit object; see below. |
4.3 benefits (per participant)
Each item in benefits is one type of service usage for that participant.
| Field | Type | Required | Description |
|---|---|---|---|
service_id | integer | Yes | Ancillary service ID from /product/services (ancillary section). e.g. General dental = 1, Major dental = 8. |
name | string | Yes | Benefit name from /product/service-benefits. Use the value field (e.g. "CheckAndClean", "SimpleExtraction", "Crown"). |
number_of_visits | string | Yes | Number of times this service is used per year by this participant. Pattern: digits only, e.g. "3". |
gross_pay | string | Yes | Out-of-pocket cost per visit (not annual). Pattern: number, optional 2 decimal places, e.g. "100" or "99.50". |
You need to map:
- Service IDs from
/product/services(ancillary). - Benefit names from
/product/service-benefits(use thevaluefield in the response).
Example for one primary:
"participants": [
{
"type": "primary",
"benefits": [
{
"service_id": 1,
"name": "CheckAndClean",
"number_of_visits": "3",
"gross_pay": "100"
},
{
"service_id": 1,
"name": "SimpleExtraction",
"number_of_visits": "2",
"gross_pay": "100"
}
]
}
]
5. Enabling the benefit calculator in the request
In filters, set:
"apply_benefit_analysis": true
You can combine this with other package-search filters (e.g. page_size, offset, display_order, hospital_classifications, show_current_policy, separate_always_include_packages). For benefit calculator, show_current_policy and show_products_from_current_fund are often set to true so the current policy appears and can be compared.
6. Capturing service usage (conversation → payload)
The calculator is only as good as the usage you send. Agents should ask:
- How many times per year they use each type of service (e.g. dentist, physio, optical).
- How much they pay out of pocket per visit for that service.
Example:
- “How many times a year do you go to the dentist?” → 3
- “Do you have extractions or similar?” → 1 or 2 a year
- “Roughly how much do you pay per visit?” → $100
Mapping into the payload:
- Check and clean:
service_id1 (General dental),name"CheckAndClean",number_of_visits"3",gross_pay"100". - Simple extraction: same
service_id1,name"SimpleExtraction",number_of_visits"2",gross_pay"100".
Use /product/services to get service_ids and /product/service-benefits to get the exact name (value) for each benefit you want to model.
7. Response structure
On success (200), the body matches the Package Search response shape, with these additions:
| Field | Location | Description |
|---|---|---|
packages | root | Same as package search, but each price in packages[].prices[] may include benefit_analysis_price. |
total | root | Total number of packages (before pagination). |
limit | root | Page size (e.g. from filters.page_size). |
applicant | root | Derived applicant info (DOB, LHC, rebate, etc.). |
benefit_analysis_previous_product | root | New. Benefit analysis result for the current policy (name, net benefits, fund, amount, benefits, total_rebate, etc.). Use this to show “your current policy” in the comparison. |
always_include_packages | root | Present when filters.separate_always_include_packages is true. Packages that are always shown (e.g. current policy). |
Each price inside packages[].prices[] can have:
| Field | Description |
|---|---|
benefit_analysis_price | null for the current policy (when it appears in the list). For other packages, an object with net benefit and switch & save figures; see below. |
8. benefit_analysis_price (per recommended package)
For each alternative package, benefit_analysis_price contains the comparison against the current policy. The most important fields for clients are the switch & save and total_rebate values.
8.1 Switch & Save (most important for “how much will I save?”)
These are the savings (or extra cost) if the customer switches from their current policy to this package. Positive = saving; negative = extra cost.
| Field | Description |
|---|---|
switch_and_save_weekly | Weekly saving (if present). |
switch_and_save_fortnightly | Fortnightly saving (including LHC). |
switch_and_save_monthly | Monthly saving (including LHC). |
switch_and_save_yearly | Yearly saving (including LHC). |
switch_and_save_fortnightly_no_lhc | Fortnightly saving excluding LHC. |
switch_and_save_monthly_no_lhc | Monthly saving excluding LHC. |
switch_and_save_yearly_no_lhc | Yearly saving excluding LHC. |
Example:
"switch_and_save_fortnightly": 33.08,
"switch_and_save_monthly": 71.28,
"switch_and_save_yearly": 855.41,
"switch_and_save_fortnightly_no_lhc": 33.08,
"switch_and_save_monthly_no_lhc": 71.28,
"switch_and_save_yearly_no_lhc": 855.41
It represents the estimated difference in what the customer pays overall when comparing their current policy to this one, based on the usage data you provided.
8.2 Net benefit
Net benefit = benefits received minus premiums. Negative means the customer pays more in premium than they get back in benefits for the usage you sent.
| Field | Description |
|---|---|
net_benefit_weekly / net_benefit_fortnightly / net_benefit_monthly / net_benefit_yearly | With LHC. |
net_benefit_*_no_lhc | Same, excluding LHC. |
When benefit analysis is on, results are ordered by switch and save (largest savings first, depending on sort order).
8.3 total_rebate and claims
benefit_analysis_price.total_rebate is an object keyed by benefit group (e.g. "DentalGeneral-DentalMajor-Endodontic"). Each value has:
| Field | Meaning |
|---|---|
rebate | Total rebate/benefit amount for that group. |
claims | Claimable amount for the usage you sent — this is what the customer can get back from this policy for that group. |
Example:
"total_rebate": {
"DentalGeneral-DentalMajor-Endodontic": {
"rebate": 498.0,
"claims": 498.0
}
}
Here, for that group the customer can claim $498 (e.g. against a $650 limit). The best policy for the customer is often not the one with the highest limit, but the one where:
- Claimable amount is close to (but within) their actual spending.
- Premium is acceptable.
- Waiting periods are acceptable.
You can use claims to explain: “With your usage, you’d get $X back from this policy for dental.”
8.4 amount and benefits
- amount — Array of pricing breakdowns (base premium, LHC, final premium by frequency). Useful for displaying premiums.
- benefits — Array of service groups with limits, waiting periods, and individual benefit policies. Useful for “what’s covered” and limits.
9. benefit_analysis_previous_product (current policy)
This root-level object describes the current policy under the same usage. It includes:
name— Combined product name (e.g. hospital + ancillary).net_benefit_*andnet_benefit_*_no_lhc— Net benefit for the current policy.fund— id, name, discount.amount— Pricing breakdown.benefits— Benefit groups and limits.total_rebate— Same structure as above (rebate and claims per group).is_current_product—true.
Use it to show “Your current policy” and compare it side by side with packages[].prices[].benefit_analysis_price for alternatives.
10. Example scenario (how the numbers fit together)
| Message | Cause |
|---|---|
benefit_analysis_data is required when apply_benefit_analysis is true | You set apply_benefit_analysis: true but omitted or invalidated benefit_analysis_data. |
Benefit calculator requires extras coverage. Hospital-only policies are not supported. | cover_type is 0 or customer has no extras. |
Membership type must match previous fund membership type | application.policy.membership_type ≠ benefit_analysis_data.previous_fund.membership_type. |
Previous fund information is required for benefit calculator | No or incomplete previous fund in application or benefit_analysis_data. |
Maximum 1 primary, 1 partner, and 5 dependents allowed | Too many or duplicate participant types. |
ancillary_product_id is required for synthetic products (separate hospital and extras) | Customer has separate hospital and extras but you didn’t send previous_fund.ancillary_product_id. |
Always check the message field in the JSON body for the exact reason.
11. Example scenario (how the numbers fit together)
- Current fund (e.g. nib): Premium $1,813.91/year. Claims (e.g. check & clean 3×, simple extraction 2×): $300 back. Net cost: $1,513.91.
- Alternative 1 (e.g. Defence Health): Premium $1,227.35/year. Claims $417.40. Net cost: $809.95. Switch & Save: $703.96/year.
- Alternative 2 (e.g. Australian Unity $750 excess): Premium $1,086.76/year. Claims $262. Net cost: $824.76. Switch & Save: $689.15/year.
The switch_and_save_yearly in the response is the difference between the current net cost and that alternative’s net cost. The “winner” is the package with the highest switch-and-save (or best net benefit) that still fits the customer’s needs (limits, waiting periods, premium).
12. Using the Benefit Calculator in sales
The response (packages, benefit_analysis_price, benefit_analysis_previous_product, total_rebate, switch & save) supports sales agents and workflows in several ways:
- Explain why a policy is recommended (limits vs usage, premium vs claims).
- Handle “switch and lose” cases (negative switch & save) by suggesting upgrades or explaining trade-offs.
- Compare current vs recommended in plain language for the customer.
Results are not always positive; some customers will see negative switch & save. In those cases, context (e.g. better long-term benefits, different usage later) can still justify a recommendation and improve conversion.
13. Full example payloads
13.1 Single member, combined product (hospital + extras in one)
{
"application": {
"personal": {
"medicare_card": true,
"previous_fund": {
"has_previous_fund": true,
"fund_id": "bup",
"fund_name": "BUPA",
"membership": 0,
"hospital_product": {
"id": 6529563,
"name": "Gold Ultimate Health Cover"
}
},
"dob": "1990-11-22"
},
"primary_address": { "state": "VIC" },
"policy": {
"membership_type": 0,
"cover_type": 2,
"lhc_age": 30,
"federal_rebate": true,
"rebate_tier": 0
}
},
"corporate_id": 1,
"filters": {
"display_order": "price_lowhi",
"page_size": [15],
"offset": 0,
"show_current_policy": true,
"show_products_from_current_fund": true,
"include_future_pricing": true,
"hospital_classifications": [
{ "code": "Bronze", "name": "Bronze", "selected": true },
{ "code": "Silver", "name": "Silver", "selected": true },
{ "code": "Gold", "name": "Gold", "selected": true }
],
"apply_benefit_analysis": true,
"separate_always_include_packages": true
},
"services": {
"hospital": [16],
"ancillary": [1, 8]
},
"benefit_analysis_data": {
"participants": [
{
"type": "primary",
"benefits": [
{ "service_id": 1, "name": "CheckAndClean", "number_of_visits": "3", "gross_pay": "100" },
{
"service_id": 1,
"name": "SimpleExtraction",
"number_of_visits": "2",
"gross_pay": "100"
}
]
}
],
"state": "VIC",
"cover_type": 2,
"membership_type": 0,
"previous_fund": {
"membership_type": 0,
"fund_name": "BUPA",
"product_type": 2,
"product_name": "Gold Ultimate Health Cover",
"hospital_product_id": 6529563
}
}
}
13.2 Family, synthetic product (separate hospital + extras)
{
"application": {
"personal": {
"medicare_card": true,
"previous_fund": {
"has_previous_fund": true,
"fund_id": "aca",
"fund_name": "ACA Health Benefits Fund",
"membership": 2,
"hospital_product": { "id": 6435350, "name": "Bronze Essentials Hospital 750" },
"ancillary_product": { "id": 6435563, "name": "Complete Ancillary" }
},
"dob": "1985-11-22"
},
"partner": { "dob": "1995-10-14" },
"primary_address": { "state": "VIC" },
"policy": {
"membership_type": 2,
"cover_type": 2,
"lhc_age": 30,
"lhc_age_partner": 30,
"federal_rebate": true,
"rebate_tier": 0
}
},
"corporate_id": 1,
"filters": {
"display_order": "price_lowhi",
"page_size": [15],
"offset": 0,
"show_current_policy": true,
"apply_benefit_analysis": true
},
"services": { "hospital": [16], "ancillary": [1, 8] },
"benefit_analysis_data": {
"participants": [
{
"type": "primary",
"benefits": [
{ "service_id": 1, "name": "CheckAndClean", "number_of_visits": "3", "gross_pay": "100" },
{
"service_id": 8,
"name": "MajorExtraction",
"number_of_visits": "2",
"gross_pay": "200"
}
]
},
{
"type": "partner",
"benefits": [
{ "service_id": 1, "name": "CheckAndClean", "number_of_visits": "4", "gross_pay": "150" },
{ "service_id": 8, "name": "Crown", "number_of_visits": "2", "gross_pay": "400" }
]
},
{
"type": "dependent_1",
"benefits": [
{ "service_id": 1, "name": "CheckAndClean", "number_of_visits": "2", "gross_pay": "80" }
]
}
],
"state": "VIC",
"cover_type": 2,
"membership_type": 2,
"previous_fund": {
"membership_type": 2,
"fund_name": "ACA Health Benefits Fund",
"product_type": 0,
"product_name": "Bronze Essentials Hospital 750",
"hospital_product_id": 6435350,
"ancillary_product_id": 6435563
}
}
}
13.3 Minimal benefit_analysis_data (for reference)
"benefit_analysis_data": {
"participants": [
{
"type": "primary",
"benefits": [
{ "service_id": 1, "name": "CheckAndClean", "number_of_visits": "3", "gross_pay": "100" },
{ "service_id": 1, "name": "SimpleExtraction", "number_of_visits": "2", "gross_pay": "100" }
]
}
],
"state": "VIC",
"cover_type": 2,
"membership_type": 0,
"previous_fund": {
"membership_type": 0,
"fund_name": "BUPA",
"product_type": 2,
"product_name": "Gold Ultimate Health Cover",
"hospital_product_id": 6529563
}
}
Related APIs
- Product Search (
GET /product/) — Find product/price IDs by fund, membership, state, policy type, and name. Use these IDs inapplication.personal.previous_fundandbenefit_analysis_data.previous_fund. - Services (
GET /product/services) — List hospital and ancillary services; use forservices.hospital/services.ancillaryand forservice_idin participants’ benefits. - Service benefits (
GET /product/service-benefits) — List benefit names per service; use thevaluefield (e.g.CheckAndClean) forbenefit_analysis_data.participants[].benefits[].name.
For full request/response schemas, enums, and examples, see the IMG Comparator API specification.