Overview
This documentation explains how to use the SolarFax API for the Profile suite of functionality, which includes API's for getting usage profile data, getting Storage+Solar recommendations, and getting Storage+Solar bill savings.
Note: using these API's incur additional fees, contact support for more information.
Basics
For the basics on using the SolarFax API, refer to this article: API Documentation.
The first thing to do to use the Profile suite of API's, is to register a profile (similar to an account or site) with an address, which gives you a profile identifier (profile_id). All other API's will take a profile_id as one of the mandatory parameters. For seamless integration, you should store the profile_id with the account in your system for future API calls.
API Endpoints
profile
- register a profileThere are four ways to register a profile:
- Address "parts" based.
Parameters:
address_one Address line one city Address city state Address state zipCode Address zip code xid (Optional) ID from your system
Example response:profile?address_one=123+East+St&city=Mountain+View&state=CA&zip_code=94043&xid=1234
{ "success": true, "message": "", "profile": { "id": 0, "xid": "1234", "utility_id": 0, "before_rate_schedule_id": 0, "before_metering_id": null, "after_rate_schedule_id": 25, "after_metering_id": 3, "created_on": "2025-08-25T22:14:11.432987", "last_update": "2025-08-25T23:13:55.578894", "utility": "PG&E" "address": { "address_one": "123 Easy St", "address_two": "", "city": "Mountain View", "state": "CA", "zip_code": "94043", "latitude": 37.3927515, "longitude": -122.0682099, }, }, }
- Address "string" based, like "123 East St, Mountain View, CA 94043"
Example request:
profile?address=123+East+St%2C+Mountain+View%2C+CA+94043
- ID lookup. This lets you get a specific profile from a profile_id.
Example request:
profile?id=1234
- XID lookup. XID is an ID field from your system if you specified it when initially registering a profile.
Example request:
profile?xid=1234
utilities
- get nearest matching utilities for a profileParameters:
profileId | ID of the profile |
searchTerm | (Optional) name filter |
Restrictions: returns first 25 results of utilities that service zip codes within a geocoded radius of the profile address. Results are given a relevance "score", where highest is most probable.
Example request:
utilities?profile_id=0
Example CURL command (use your api-key and access-token):
curl -H 'Api-Key: KEY' -H 'Access-Token: TOKEN' -G -d 'profile_id=0' https://api.solardatapros.com/api/v1/utilities
Example response:
{
"success": true,
"message": "",
"best_utility_id": 1,
"last_utility_id": 1,
"count": 1,
"utilities": [
{
"id": 1,
"name": "Pacific Gas & Electric Co.",
"short_name": "PG&E",
"short_name_alias": "Pacific Gas",
"type": 1,
"website": null,
"ownership_type": "Investor Owned",
"score": 1140,
"rate_res": 0.27084566974395236,
"rate_comm": 0.2504424822592163
}
]
}
Selecting the Initial Utility
To help you select the initial utility for a profile, two fields should be used: last_utility_id (the last utility used by this profile), and best_utility_id (highest score). Here is example Javascript code to determine the selected utility_id:
var selected_utility_id = null;
// Select the last, then best, then first in order
if (last_utility_id) {
selected_utility_id = last_utility_id;
} else if (best_utility_id) {
selected_utility_id = best_utility_id;
} else if (result.utilities.length) {
selected_utility_id = result.utilities[0].id;
}
rate_schedules
- get rate scheduled for a utilityParameters:
profile_id | ID of the profile |
utility_id | ID of the utility |
sector_id | ID of the sector. 1 = Residential, 2 = Commercial, unspecified = All |
Results are given a relevance "score", where highest is most probable.
Example request:
rate_schedules?profile_id=0&utility_id=0§or_id=0
Example CURL command (use your api-key and access-token):
curl -H 'Api-Key: KEY' -H 'Access-Token: TOKEN' -G -d 'profile_id=0' -d 'utility_id=0' https://api.solardatapros.com/api/v1/rate_schedules
Example response:
{
"success": true,
"message": "",
"best_rate_schedule_id": 378,
"best_rate_schedule_metering_id": null,
"solar_rate_schedule_id": 1,
"solar_rate_schedule_metering_id": 3,
"last_before_rate_schedule_id": 378,
"last_before_rate_schedule_metering_id": null,
"last_after_rate_schedule_id": 1,
"last_after_rate_schedule_metering_id": 3,
"count": 2,
"rate_schedules": [
{
"id": 378,
"name": "E-1 -Residential Service Baseline",
"short_name": null,
"short_name_alias": "E-1 -RES Svc Baseline",
"provider_id": 1,
"is_default": true,
"source_url": "https://www.pge.com/tariffs/assets/pdf/tariffbook/ELEC_SCHEDS_E-1.pdf",
"sector": "Residential",
"average_rate": 0.4,
"metering_id": null,
"metering": null,
"score": 11
},
{
"id": 1,
"name": "E-ELEC Residential Time of Use (Electric Home) - NBT",
"short_name": "None - NBT",
"short_name_alias": "E-ELEC RES TOU (Electric Home)",
"provider_id": 1,
"is_default": null,
"source_url": "https://www.pge.com/tariffs/assets/pdf/tariffbook/ELEC_SCHEDS_E-ELEC.pdf",
"sector": "Residential",
"average_rate": 0.39,
"metering_id": 3,
"metering": "NBT",
"score": 3
},
]
}
Rate Schedule Metering
Using rate schedules requires both an ID (rate_schedule_id) and a Metering (metering_id). Metering values are utility specific and by default is NULL. Metering is very important when needed - for example the California Investor owned utilities (PGE, SCE, SDGE) use metering values 2 (NEM2) and 3 (NEM3 / NBT) to specify the net metering for billing, specifically post adding solar. This concept will mostly be handled for you, where each rate schedule will have both an id
and a metering_id
- just be sure to pass both values to API's that need them.
To calculating savings when running a scenario, you will need a "before" rate schedule, and an "after" rate schedule. This allows you to do two things: first, you can see how switching a rate schedule would effect the bill, and second (if the scenario includes adding solar), allows you to change to a specified solar rate schedule if the utility requires it.
Selecting the Initial "Before" Rate Schedule
To help you select the initial "before" rate schedule for a profile, two combination fields should be used: last_before_rate_schedule_id
/ last_before_rate_schedule_metering_id
(the last rate schedule used by this profile), and best_rate_schedule_id
/ best_rate_schedule_metering_id
(highest score).
Here is example Javascript code to determine the selected "before" rate_schedule_id:
var selected_rate_schedule_id = null, selected_metering_id = null;
// Select the last, then best, then first in order
if (last_before_rate_schedule_id) {
selected_rate_schedule_id = last_before_rate_schedule_id;
selected_metering_id = last_before_rate_schedule_metering_id;
} else if (best_before_rate_schedule_id) {
selected_rate_schedule_id = best_before_rate_schedule_id;
selected_metering_id = best_before_rate_schedule_metering_id;
} else if (result.rate_schedules.length) {
selected_rate_schedule_id = result.rate_schedules[0].id;
selected_metering_id = result.rate_schedules[0].metering_id;
}
Selecting the Initial "After" Rate Schedule
To help you select the initial "after" rate schedule for a profile, three combination fields should be used: solar_rate_schedule_id
/ solar_rate_schedule_metering_id
(if adding solar), last_before_rate_schedule_id
/ last_before_rate_schedule_metering_id
(the last rate schedule used by this profile), and best_rate_schedule_id
/ best_rate_schedule_metering_id
(highest score).
Solar Rate Schedules
Some utilities require a specific rate schedule / metering when adding solar - an example is the California IOU's, where PG&E requires switching to E-ELEC and NBT/NEM3. If it is required, this will be specified by the solar_rate_schedule_id
/ solar_rate_schedule_metering_id
fields.
Here is example Javascript code to determine the selected "after" rate_schedule_id:
var selected_rate_schedule_id = null, selected_metering_id = null;
var solar = true;
// Select the solar, then last, then best, then first in order
if (solar && solar_rate_schedule_id) {
selected_rate_schedule_id = solar_rate_schedule_id;
selected_metering_id = solar_rate_schedule_metering_id;
} else if (last_after_rate_schedule_id) {
selected_rate_schedule_id = last_after_rate_schedule_id;
selected_metering_id = last_after_rate_schedule_metering_id;
} else if (best_after_rate_schedule_id) {
selected_rate_schedule_id = best_after_rate_schedule_id;
selected_metering_id = best_after_rate_schedule_metering_id;
} else if (result.rate_schedules.length) {
selected_rate_schedule_id = result.rate_schedules[0].id;
selected_metering_id = result.rate_schedules[0].metering_id;
}
load_profile
- get nearest match hourly load profile for a profileParameters:
profile_id | ID of the profile |
utility_id | ID of the utility |
rate_schedule_id | ID of the rate schedule |
rate_schedule_metering_id | ID of the rate schedule metering |
Example request:
load_profile?profile_id=0&utility_id=0&rate_schedule_id=0&rate_schedule_metering_id=null
Example response:
{
"success": true,
"message": "",
"usage": {
"net_kWh": 8261.55,
"annual_cost": 4108.19,
"intervals": [
{
"start": "2024-01-01T00:00:00",
"pull": 709613,
"push": 0,
"net": 709613
},
... [ 8760 hourly values ] ...
{
"start": "2024-12-31T23:00:00",
"pull": 981554,
"push": 0,
"net": 981554
}
],
"monthly_costs": [
356.58,
320.29,
312.29,
282.17,
285.03,
347.67,
392.68,
407.93,
409.42,
341.96,
304.6,
347.57
],
"duration": 60,
"units": "mWh"
},
}
Hourly Interval Data
The usage
field returns a year of hourly interval data, where each hour specifies the start date/time, and the push/pull/net usage values. The duration
field is in minutes, where 60 means hourly. The units
field specifies the unit of each value, currently this is "mWh" (milliwatt-hours). This allows integer math (no decimals), where you can covert final values to kWh (kilowatt-hours):
kwh = mwh * 1e-6 // Move 6 decimal places
Costs
By passing a rate schedule, the monthly bills are calculated for you and returned in the monthly_costs
field (an array of 12 monthly values). These are calculated down to the hour using the correct rates (including Time of Use), and are not an average value.
modify_consumption
- modify hourly consumption dataThis API is used to modify hourly consumption data. This data can be from the load_profile API, or it can be actual data from a CSV or data provider (including SolarFax). It allows you to modify the consumption by giving "one number", currently one month of consumption or the annual consumption - the consumption data is scaled based on that.
Example: if the annual consumption is 10,000 kWh and you pass 20,000 as the modifiers_annual_kwh
parameter, the consumption would be doubled.
This API allows you to have an interactive UI similar to this:
Parameters:
profile_id | ID of the profile |
usage_data | hourly consumption data |
utility_id | ID of the utility |
rate_schedule_id | ID of the rate schedule |
rate_schedule_metering_id | ID of the rate schedule metering |
modifiers_annual_kwh | Modified annual consumption |
modifiers_monthly_kwh | Modified monthly consumption (array) |
Example request (POST data):
{
profile_id: 0,
usage_data: [
{
"start": "2024-01-01T00:00:00",
"pull": 709613,
"push": 0,
"net": 709613
},
... [ 8760 hourly values ] ...
],
utility_id: 0,
rate_schedule_id: 0,
rate_schedule_metering_id: null,
modifiers_monthly_kwh: [null, null, null, null, null, 500, null, null, null, null, null, null],
modifiers_annual_kwh: null,
}
Example response (same as response from the load_profile API):
{
"success": true,
"message": "",
"usage": {
"net_kWh": 8261.55,
"annual_cost": 4108.19,
"intervals": [
{
"start": "2024-01-01T00:00:00",
"pull": 709613,
"push": 0,
"net": 709613
},
... [ 8760 hourly values ] ...
{
"start": "2024-12-31T23:00:00",
"pull": 981554,
"push": 0,
"net": 981554
}
],
"monthly_costs": [
356.58,
320.29,
312.29,
282.17,
285.03,
347.67,
392.68,
407.93,
409.42,
341.96,
304.6,
347.57
],
"duration": 60,
"units": "mWh"
},
}
This API returns the same payload as the load_profile API, so they are interchangeable.
recommendation
- Storage+Solar recommendationThis API is used to analyze a year of hourly consumption data, and give recommendations for storage sizing (batteries) and solar system sizing (production). It currently returns a "min" and "max" recommendation, where min is enough to cover consumption during peak hours (the most expensive energy), and max is enough to cover peak+overnight (maximize grid independence).
Parameters:
profile_id | ID of the profile |
usage_data | hourly consumption data |
utility_id | ID of the utility |
rate_schedule_id | ID of the rate schedule |
rate_schedule_metering_id | ID of the rate schedule metering |
Example request (POST data):
{
profile_id: 0,
usage_data: [
{
"start": "2024-01-01T00:00:00",
"pull": 709613,
"push": 0,
"net": 709613
},
... [ 8760 hourly values ] ...
],
utility_id: 0,
rate_schedule_id: 0,
rate_schedule_metering_id: null,
}
Example response:
{
"success": true,
"message": "",
"recommendations": {
"min": {
"battery": 7.5,
"nearest_battery": 10,
"production": 4324.41,
"system_size": 2.88,
"consumption_offset": 52.3
},
"max": {
"battery": 13.5,
"nearest_battery": 15,
"production": 6131.62,
"system_size": 4.09,
"consumption_offset": 74.2
}
}
}
This API request usage_data is the same payload as returned by the load_profile and modify_consumption API's, so you can pass them forward.
Battery Recommendation
Each recommendation contains the specific battery size battery
(kWh), then the nearest battery nearest_battery
, which is rounded to a multiple of the allowed battery sizes you setup in advance (kWh) - this is the value you should use.
Solar Recommendation
Each recommendation contains the production
(kWh), system_size
(kW) and consumption_offset
(%).
savings
- Savings from adding Storage+SolarThis API calculates the bill savings by adding storage+solar to a consumption profile, and/or changing the rate schedule. This is calculated down to the hour using the correct rates (including Time of Use), and are not average values.
Parameters:
profile_id | ID of the profile |
usage_data | hourly consumption data |
utility_id | ID of the utility |
before_rate_schedule_id | ID of the rate schedule "before" |
before_rate_schedule_metering_id | ID of the rate schedule metering "before" |
after_rate_schedule_id | ID of the rate schedule "after" |
after_rate_schedule_metering_id | ID of the rate schedule metering "after" |
battery_size | Storage to add (kWh) |
production | Production to add (kWh) |
Example request (POST data):
{
profile_id: 0,
usage_data: [
{
"start": "2024-01-01T00:00:00",
"pull": 709613,
"push": 0,
"net": 709613
},
... [ 8760 hourly values ] ...
],
utility_id: 0,
before_rate_schedule_id: 0,
before_rate_schedule_metering_id: null,
after_rate_schedule_id: 1,
after_rate_schedule_metering_id: 3,
battery_size: 10,
production: 4324,
}
Example response:
{
"success": true,
"message": "",
"savings": {
"usage_cost_before": 341.5,
"usage_cost_after": 121.25,
"base_fee_before": 0,
"base_fee_after": 15,
"savings": 205.25
}
}
This API request usage_data
is the same payload as returned by the load_profile and modify_consumption API's, so you can pass them forward. The battery_size
and production
values can come directly from the recommendation API result.
Savings
The response contains the average monthly usage cost before usage_cost_before
($), the average monthly usage_cost after usage_cost_after
($), the average monthly base fee before base_fee_before ($), the average monthly base fee after base_fee_after
($), and the average monthly savings savings
($). All values are for the first year.
Here is an example graph from these values: