Qualifications
Every program returned by GET /programs can include a qualifications array and an optional qualifier expression. Qualifications define conditions that must be met before a participant's potential earnings are considered qualified — they gate whether an offer pays out at all.
There are currently seven qualification types: aggregated_amount, aggregated_quantity, brand_count, share_of_wallet_percent, yoy_amount_index, amount_average_index, and property.
At a Glance
| Qualification Type | What It Measures | Typical Use Case |
|---|---|---|
| Aggregated Amount | Total dollar amount of matching transactions | "Buy at least $100,000 of crop protection to qualify" |
| Aggregated Quantity | Total quantity of matching transactions | "Purchase at least 500 gallons to qualify" |
| Brand Count | Count of distinct matching brands | "Buy across at least 2 herbicide brands to qualify" |
| Share of Wallet Percent | Ratio of one product group's volume to another | "At least 30% of your herbicide acres must be our brand" |
| YoY Amount Index | Year-over-year dollar comparison | "Purchase the same or more than last year" |
| Amount Average Index | Comparison of amounts with averaging | "Current year purchases must meet or exceed the 3-year average" |
| Property | An externally provided value from the request | "Business plan must be marked as achieved" |
Core Concepts
Qualification vs. Qualifier
These two terms are related but distinct:
- Qualification — a single measurable condition (e.g., "total purchases ≥ $50,000"). Each qualification evaluates independently and produces a
met/not metresult. - Qualifier — a boolean expression that combines one or more qualification results using
AND/ORlogic to determine the finalqualifiedstatus for a program or offer. For example:"purchase_volume AND (loyalty_tier OR business_plan_achieved)".
If no qualifier expression is provided, the program or offer is considered qualified by default.
Evaluation Levels
Qualifications can be defined at two levels:
| Level | Scope | Effect |
|---|---|---|
| Program | All offers in the program | If the program qualifier evaluates to false, none of its offers are evaluated |
| Offer | A single offer | If the offer qualifier evaluates to false, that specific offer does not pay out |
Program-level qualifications are evaluated first. Only offers belonging to qualified programs proceed to offer-level qualification evaluation.
Operators
Every qualification compares an actual computed value against a target using an operator:
| Operator | Meaning |
|---|---|
greater_than_or_equal_to |
Actual must be ≥ target |
greater_than |
Actual must be > target |
less_than_or_equal_to |
Actual must be ≤ target |
less_than |
Actual must be < target |
equal_to |
Actual must exactly equal target |
Waiving Qualifications
Qualifications can be waived per request by passing a waive_qualifications property in the calculation request. A waived qualification is treated as met regardless of the actual computed value — the waived: true flag is set in the response while met reflects the real evaluation.
{
"properties": [
{
"type": "waive_qualifications",
"key": "waive_qualifications",
"value": [
{
"program_key": "corteva.2026.retailer.national.crop_protection",
"qualification_key": "minimum_purchase_volume",
"offer_key": null
}
]
}
]
}
When offer_key is null, the waiver applies to the qualification at the program level. When an offer_key is specified, only that offer's instance of the qualification is waived.
Qualification Types
Aggregated Amount
Sums the dollar amount of transactions matching the specified filters and compares the total against a target value. This is the most common qualification type.
Programs Response
{
"type": "aggregated_amount",
"key": "minimum_cp_purchases",
"label": "Minimum Crop Protection Purchases",
"operator": "greater_than_or_equal_to",
"value": 100000.0,
"filters": [
{
"period_key": "incentive_period",
"sku_keys": ["agri_shield_insecticide_2.5_gal_53551", "agri_shield_insecticide_bulk_63374", "crop_guard_30_l_herbicide_2.5_gal_22654"],
"transaction_type": "retailer_purchases_from_distribution"
}
],
"attributes": []
}
Reading this: The participant must purchase at least $100,000 worth of agri_shield_insecticide_2.5_gal_53551, agri_shield_insecticide_bulk_63374, and crop_guard_30_l_herbicide_2.5_gal_22654 during the incentive_period from distribution. The dollar amounts of all matching transactions are summed and compared against the target.
Note
The filters can include multiple entries with different period keys, SKU sets, or transaction types. All matching transactions across all filter entries are summed together.
Aggregated Quantity
Sums the quantity of transactions matching the specified filters. Identical in structure to aggregated_amount, but measures units purchased rather than dollars spent.
Programs Response
{
"type": "aggregated_quantity",
"key": "minimum_gallons_purchased",
"label": "Minimum Gallons Purchased",
"operator": "greater_than_or_equal_to",
"value": 500.0,
"filters": [
{
"period_key": "incentive_period",
"sku_keys": ["agri_shield_insecticide_2.5_gal_53551"],
"transaction_type": "retailer_purchases_from_distribution"
}
],
"attributes": []
}
Reading this: The participant must purchase at least 500 units of the specified SKU during the incentive_period. The quantity from each matching transaction is summed.
Share of Wallet Percent
Measures the ratio of one product group's volume to another, expressed as a percentage. This is used when a manufacturer wants to ensure a minimum share of a participant's total business in a category.
The qualification has a numerator and denominator, each with their own filters:
- Numerator — the product group being measured (e.g., "our brand's herbicide")
- Denominator — the total category (e.g., "all herbicide from any brand")
- Target — the minimum percentage the numerator must represent of the denominator
Programs Response
{
"type": "share_of_wallet_percent",
"key": "herbicide_share_of_wallet",
"label": "Herbicide Share of Wallet",
"operator": "greater_than_or_equal_to",
"value": 30.0,
"numerator": {
"filters": [
{
"period_key": "incentive_period",
"sku_keys": ["harvest_max_pro_herbicide_2.5_gal_46367", "harvest_max_pro_herbicide_bulk_73826"],
"transaction_type": "retailer_purchases_from_distribution"
}
]
},
"denominator": {
"filters": [
{
"period_key": "incentive_period",
"sku_keys": ["harvest_max_pro_herbicide_2.5_gal_46367", "harvest_max_pro_herbicide_bulk_73826", "knock_down_herbicide_2.5_gal_44159", "knock_down_herbicide_bulk_52335"],
"transaction_type": "retailer_purchases_from_distribution"
}
]
},
"attributes": []
}
Reading this: The participant's purchases of harvest_max_pro_herbicide_2.5_gal_46367 and harvest_max_pro_herbicide_bulk_73826 must represent at least 30% of their total herbicide purchases (including competitor products). The engine computes the target as denominator_amount × 30 / 100 and compares the numerator amount against it.
YoY Amount Index
Compares the current year dollar amount against a prior year amount to measure year-over-year growth. Like share of wallet, this uses a numerator/denominator structure:
- Numerator — current year transactions
- Denominator — prior year transactions
- Target — the index value the ratio must meet (e.g.,
100.0means "match or exceed last year")
Programs Response
{
"type": "yoy_amount_index",
"key": "yoy_growth_requirement",
"label": "Year-over-Year Growth",
"operator": "greater_than_or_equal_to",
"value": 100.0,
"numerator": {
"filters": [
{
"period_key": "incentive_period",
"sku_keys": ["agri_shield_insecticide_2.5_gal_53551", "agri_shield_insecticide_bulk_63374"],
"transaction_type": "retailer_purchases_from_distribution"
}
]
},
"denominator": {
"filters": [
{
"period_key": "prior_year_period",
"sku_keys": ["agri_shield_insecticide_2.5_gal_53551", "agri_shield_insecticide_bulk_63374"],
"transaction_type": "retailer_purchases_from_distribution"
}
]
},
"attributes": []
}
Reading this: The participant's current year purchases must be at least 100% of their prior year purchases (i.e., no decline). The numerator sums current-period transactions; the denominator sums prior-period transactions. The engine computes the target as the denominator amount scaled by the index value.
Note
If the denominator (prior year) is zero or negative, the qualification is automatically considered met — you can't grow relative to nothing.
Amount Average Index
Similar to YoY Amount Index but supports averaging over multiple periods using a divisor. This allows comparisons like "current year vs. 3-year average."
Programs Response
{
"type": "amount_average_index",
"key": "three_year_average_growth",
"label": "3-Year Average Growth Requirement",
"operator": "greater_than_or_equal_to",
"value": 100.0,
"numerator": {
"filters": [
{
"period_key": "incentive_period",
"sku_keys": ["agri_shield_insecticide_2.5_gal_53551"],
"transaction_type": "retailer_purchases_from_distribution"
}
]
},
"denominator": {
"filters": [
{
"period_key": "prior_three_year_period",
"sku_keys": ["agri_shield_insecticide_2.5_gal_53551"],
"transaction_type": "retailer_purchases_from_distribution"
}
],
"divisor": 3.0
},
"attributes": []
}
Reading this: The participant's current year purchases must meet or exceed 100% of their average annual purchases over the prior three years. The denominator total is divided by 3.0 before comparison.
Brand Count
Counts the number of distinct brands represented by transactions matching the specified filters, then compares that count against a target value. This is useful when a program requires a participant to buy across multiple brands rather than just multiple SKUs from the same brand.
A brand count qualification can further refine the set being counted with:
brand_keys— the brands that are eligible to count toward the totalexcluded_sku_keys— specific SKUs to ignore even if they would otherwise match the filters
Programs Response
{
"type": "brand_count",
"key": "minimum_herbicide_brand_count",
"label": "Minimum Herbicide Brand Count",
"operator": "greater_than_or_equal_to",
"value": 2,
"filters": [
{
"period_key": "incentive_period",
"sku_keys": [
"harvest_max_pro_herbicide_2.5_gal_46367",
"harvest_max_pro_herbicide_bulk_73826",
"knock_down_herbicide_2.5_gal_44159",
"knock_down_herbicide_bulk_52335",
"crop_guard_30_l_herbicide_2.5_gal_22654"
],
"transaction_type": "retailer_purchases_from_distribution"
}
],
"brand_keys": [
"harvest_max_pro_herbicide",
"knock_down_herbicide",
"crop_guard_30_l_herbicide"
],
"excluded_sku_keys": ["knock_down_herbicide_bulk_52335"],
"attributes": []
}
Reading this: The participant must purchase qualifying products from at least 2 distinct brands during the incentive_period. Only the listed brand_keys count toward the total, and knock_down_herbicide_bulk_52335 is ignored even if it appears in matching transactions.
Property
Uses an externally provided value from the calculation request rather than computing a value from transactions. This is for conditions that the engine cannot derive from transaction data — business metrics, certifications, plan achievements, etc.
A property qualification specifies:
property.key— the key to look up in the request's propertiesproperty.type—numberorbooleanproperty.level— where the property is provided:request,entity, ortransaction
Programs Response — Numeric Property
{
"type": "property",
"key": "business_plan_achievement",
"label": "Business Plan Achievement",
"operator": "greater_than_or_equal_to",
"value": 85.0,
"property": {
"key": "business_plan_achieved_percent",
"type": "number",
"level": "request"
},
"attributes": []
}
Reading this: The requestor must pass a business_plan_achieved_percent property at the request level with a value of at least 85.0. This is an externally maintained metric — the engine uses whatever value is provided.
Programs Response — Boolean Property
{
"type": "property",
"key": "sustainability_certified",
"label": "Sustainability Certification",
"operator": "equal_to",
"value": true,
"property": {
"key": "is_sustainability_certified",
"type": "boolean",
"level": "entity"
},
"attributes": []
}
Reading this: The entity must have is_sustainability_certified set to true. Boolean properties always use equal_to as the operator.
Calculations Response
The calculations response includes a qualification_results array alongside potential_earnings. Each entry reports the evaluation outcome for one qualification:
{
"qualification_results": [
{
"offer_key": "corteva.2026.retailer.national.crop_protection.base",
"qualification_key": "minimum_cp_purchases",
"met": true,
"waived": false,
"target": "100000",
"operator": "greater_than_or_equal_to",
"actual": "128500",
"difference": "28500"
},
{
"offer_key": "corteva.2026.retailer.national.crop_protection.base",
"qualification_key": "yoy_growth_requirement",
"met": false,
"waived": false,
"target": "115000",
"operator": "greater_than_or_equal_to",
"actual": "108000",
"difference": "-7000"
}
]
}
Reading this:
| Field | Meaning |
|---|---|
offer_key |
The offer this qualification applies to |
qualification_key |
The key from the qualification definition |
met |
Whether the actual value satisfied the operator + target |
waived |
Whether this qualification was waived in the request |
target |
The threshold value that must be met |
operator |
How actual is compared to target |
actual |
The computed value from transactions (or the provided property value) |
difference |
actual - target — positive means the target was exceeded, negative means it was not met |
Note
Qualification results are flattened to the offer level. Program-level qualifications are duplicated across all offers in the program, so each offer row is self-contained.
The Qualifier Expression
The qualifier field on a program or offer is a boolean expression that combines qualification keys with AND and OR operators. The engine evaluates each qualification independently, then substitutes the results into the expression to determine the final qualified status.
This means: the program is qualified only if both minimum_cp_purchases and yoy_growth_requirement are met (or waived).
More complex expressions are supported:
This means: must meet minimum_cp_purchases and at least one of the other two.
If qualifier is null or absent, the program/offer is considered qualified regardless of individual qualification results.
Summary
- Qualifications gate whether offers pay out by evaluating measurable conditions against targets
- Seven types cover transaction aggregates, brand counts, ratios, year-over-year comparisons, averages, and externally provided values
- Qualifiers combine qualification results with boolean logic (
AND/OR) to determine the final qualified status - Qualifications can be waived per request without changing the underlying evaluation
- Results include
met,waived,target,actual, anddifferencefor full transparency