Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.incentives.leap.energy/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The Incentives API calculates incentives across multiple utility programs for a customer address and device. It automatically handles customer creation, utility lookup, and incentive aggregation. For detailed endpoint specifications, see the Check Incentives API reference.

Operation Types

The Incentives API supports three operation modes:

lookup Operation

Use for first-time customers or when you need fresh utility data:
  • Required fields: address, building_type, and device_ids or device_names
  • Creates a new customer if not found
  • Geocodes the address to find applicable utilities
  • Caches utility data on the customer record for future use
  • Creates customer_device records for all devices (including duplicates when using device_ids)
  • Slower due to address processing and utility lookup
  • Device handling: On first call, creates all devices as customer devices. On subsequent calls, validates that all devices already exist for the customer.

refresh Operation

Use for returning customers with cached utility data (faster):
  • Required fields: Only reference_id
  • Customer must already exist
  • Optional fields:
    • address: If provided and differs from stored address, updates customer address (still uses cached utilities, no geocoding)
    • building_type: If not provided, resolved from customer’s stored building_type_id in the database
    • device_ids:
      • If not provided: Uses all existing devices from customer’s customer_devices table
      • If provided: Validates that all device_ids already exist for the customer, then uses those devices
  • Significantly faster—no geocoding or utility lookup required
  • Uses cached utility data from previous lookup
  • Device handling: Without device_ids, uses all existing devices. With device_ids, validates they exist before using them.
device_names is not supported for refresh operations. Use device_ids to specify devices, or omit devices entirely to use all existing devices.

override Operation

Use when a customer changes their devices completely:
  • Required fields: reference_id, building_type, and device_ids or device_names
  • Customer must already exist
  • Optional fields:
    • address: If provided and differs from stored address, updates customer address (still uses cached utilities, no geocoding)
  • Device handling: Deletes ALL existing customer devices, then creates new ones from the provided devices
  • Then refreshes calculation using cached utilities (faster than lookup)
  • Use when you need to completely replace a customer’s device list without validation errors
Performance Tip: Always use operation_type="refresh" for returning customers with the same devices. This skips geocoding and uses cached utility data, providing much faster responses. Use override only when devices have changed.

Reference IDs

The reference_id field is required and serves multiple purposes:
  • Must be unique within your account
  • Enables fast lookups on subsequent API calls
  • Use your internal customer/account ID for easy correlation
Reference IDs are scoped to your account. The same reference_id can exist in different customer accounts without conflict.

Creating Applications

Set create_application: true in the Incentives request to automatically create application records. When enabled, the response includes a connect_url field with a link to the customer application portal. This streamlines the workflow by combining incentive calculation and application creation in a single API call.

Device IDs

The device_ids field is an array that can contain multiple device IDs, including duplicates:
  • Array format: device_ids: [42, 44, 44, 44] creates 4 customer device records (1 for device 42, 3 for device 44)
  • Device categories: The API extracts unique device categories from all device_ids and looks up programs for all device types (e.g., EV Chargers, Thermostats, Heat Pumps)
  • Required for: lookup and override operations
  • Optional for: refresh operation (uses existing devices if not provided)
When using refresh without device_ids, the API uses all existing devices from the customer’s customer_devices table. This allows refreshing with just the reference_id.

Device Names

As an alternative to device_ids, you can pass device_names — an array of your own equipment or product name strings. The API resolves these to Leap device IDs using your organization’s equipment map.
  • Supported for: lookup and override operations
  • Not supported for: refresh operations
  • Mutually exclusive with device_ids — providing both returns a 400 error

Resolution Behavior

The API matches each name against your organization’s equipment map and resolves it to a Leap device ID:
  • All names resolve: The request proceeds normally using the resolved device IDs.
  • Partial resolution: The request proceeds with the resolved devices. The response includes a warnings object listing the unresolved names so you can update your equipment map.
  • Zero resolution: The request fails with a 400 error and an unresolved_device_names array listing the names that could not be matched.
When the response includes a warnings.unresolved_device_names array, review the listed names and work with Leap to update your equipment map. Future requests with those names will then resolve automatically.

Example Response with Warnings

When some device names cannot be resolved, the response includes a warnings object alongside the normal incentive results:
{
  "utility": { "eiaid": "14354", "name": "PacifiCorp (Oregon)" },
  "address": "456 Oak Ave, Portland, OR 97201",
  "building_type": "RESIDENTIAL",
  "customer_id": 790,
  "programs_evaluated": 2,
  "incentives": {
    "total_incentive_amount": 1500,
    "total_eligible_combinations": 1,
    "by_program": [...]
  },
  "reference_id": "external-ref-456",
  "warnings": {
    "unresolved_device_names": ["Unknown Model XYZ"],
    "message": "1 device name(s) could not be resolved and were skipped."
  }
}

Example Workflow

First-Time Customer (Lookup)

curl -X POST "https://api.incentives.leap.energy/alpha/incentives" \
  -H "x-api-key: leap_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operation_type": "lookup",
    "reference_id": "customer-123",
    "address": {
      "street_1": "123 Main St",
      "city": "San Francisco",
      "state_or_province_code": "CA",
      "postal_code": "94102",
      "country_code": "US"
    },
    "building_type": "RESIDENTIAL",
    "device_ids": [42],
    "create_application": true
  }'

First-Time Customer (Lookup with Device Names)

curl -X POST "https://api.incentives.leap.energy/alpha/incentives" \
  -H "x-api-key: leap_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operation_type": "lookup",
    "reference_id": "customer-456",
    "address": {
      "street_1": "456 Oak Ave",
      "city": "Portland",
      "state_or_province_code": "OR",
      "postal_code": "97201",
      "country_code": "US"
    },
    "building_type": "RESIDENTIAL",
    "device_names": ["Mitsubishi Hyper-Heat MSZ-RXT09", "Rheem ProTerraDERA2060"],
    "create_application": true
  }'

Returning Customer (Refresh - Minimal)

curl -X POST "https://api.incentives.leap.energy/alpha/incentives" \
  -H "x-api-key: leap_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operation_type": "refresh",
    "reference_id": "customer-123",
    "create_application": true
  }'

Returning Customer (Refresh - With Device Validation)

curl -X POST "https://api.incentives.leap.energy/alpha/incentives" \
  -H "x-api-key: leap_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operation_type": "refresh",
    "reference_id": "customer-123",
    "device_ids": [42, 44],
    "create_application": true
  }'

Customer Changed Devices (Override)

curl -X POST "https://api.incentives.leap.energy/alpha/incentives" \
  -H "x-api-key: leap_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operation_type": "override",
    "reference_id": "customer-123",
    "building_type": "RESIDENTIAL",
    "device_ids": [55, 66, 77],
    "create_application": true
  }'

Best Practices

Choose the Right Operation Type

  • First interaction: Use lookup with full address and device_ids or device_names
  • Subsequent calls (same devices): Use refresh with just the reference_id (fastest option)
  • Subsequent calls (validate specific devices): Use refresh with reference_id and device_ids
  • Customer changed devices: Use override to replace all devices
  • Address changes: Use lookup to update utility information (geocodes new address)

Device ID Strategy

  • Use arrays for device_ids even for single devices: [42] not 42
  • Include duplicates in the array if customer has multiple of the same device: [42, 42, 42]
  • For refresh operations, you can omit device_ids to use all existing devices
  • For override operations, provide the complete new device list (old devices are deleted)

Device Name Strategy

  • Use device_names when you have equipment model names or product strings but not Leap device IDs
  • Check the warnings object in the response to catch unresolved names early
  • device_names works with lookup and override operations only — use device_ids for refresh
  • You cannot combine device_ids and device_names in the same request

Reference ID Strategy

  • Use your internal customer/account ID as the reference_id
  • Maintain consistency across all API calls for the same customer
  • Store the mapping between your IDs and Leap’s customer_id for reference
  • Reference IDs are scoped to your organization (same ID can exist in different organizations)

Error Responses

Non-2xx responses follow a consistent shape:
{
  "error": "No utility found for this address",
  "error_code": "no_utility_at_address",
  "details": {
    "upstream": "utility-programs-lookup",
    "upstream_status": 404
  }
}
  • error — human-readable message, suitable for logs or support tickets. May be revised over time.
  • error_code — stable, typed identifier. Build retry logic and branching against error_code, not against the message.
  • details — optional diagnostic payload whose shape varies by error_code.

Error code reference

error_codeStatusWhen it happensRetry?
no_utility_at_address404Address is not covered by any known utility in our territory dataNo — address is not serviceable; contact Leap if you believe this is a gap in our data
address_not_geocodable422Address could not be resolved by the geocoderNo — correct the address and resubmit
no_valid_eiaid404Matched utilities are missing EIA IDs in our catalogNo — contact Leap
invalid_building_type400building_type is not a supported valueNo — use RESIDENTIAL, MULTIFAMILY, MANUFACTURED_HOME, or COMMERCIAL
building_type_unresolved400Could not resolve building type during a refreshNo — include building_type explicitly
invalid_json_body400Request body was not valid JSONNo
mutually_exclusive_device_inputs400Request included both device_ids and device_namesNo — send one or the other
device_names_not_supported_for_refresh400device_names is not supported for refreshNo — use device_ids or omit devices
missing_devices400device_ids / device_names required for lookup or overrideNo
no_device_categories400Provided device_ids don’t exist in our catalogNo
upstream_transient502Transient upstream failure (geocoder, programs service)Yes — exponential backoff
upstream_infra502Upstream infrastructure errorYes — exponential backoff
device_name_resolution_failed500Internal error resolving device namesYes — exponential backoff
delete_customer_devices_failed500Internal error during overrideYes — exponential backoff
cached_utilities_read_failed500Internal error reading cached utilitiesYes — exponential backoff
internal_error500Unexpected server errorYes — exponential backoff
Rule of thumb: retry on 5xx, don’t retry on 4xx. The details.upstream_* fields on 5xx responses help Leap support diagnose upstream issues — include them if you file a ticket.
A small number of validation errors (e.g. reference ID mismatches, missing required fields on new-customer creation) currently return 4xx responses without an error_code field. When error_code is absent, fall back to matching on the error message. These paths are being migrated to the typed system.

Retry strategy

For 5xx errors, use exponential backoff — start at 1 second, double up to a cap of ~30 seconds, with a total retry budget around 60 seconds. Add random jitter to avoid thundering herd. Do not retry 4xx responses. They indicate a request-level problem that won’t resolve without a change on your end (or a data fix on ours).

Common scenarios

  • No utility found (no_utility_at_address, 404): the address does not match any utility service territory in our data. This is not a transient failure — retrying the same address will return the same result. If you believe the address should be serviced, report it to Leap with the details.upstream_body fields so we can investigate the territory polygon.
  • Reference ID mismatch (400, no error_code yet): the customer already exists in your account under a different reference_id. Use the original reference_id for this customer, or use a new one for a new customer.
  • Device not found on refresh: when using refresh with device_ids, all IDs must already be associated with the customer. Use override if you need to replace the device list.
  • Unresolved device names: if zero names resolve, the request returns 400 with an unresolved_device_names array. If some resolve, the request succeeds and the response includes warnings.unresolved_device_names — update your equipment map for future calls.