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 zip_code 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:
profile_id | 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,
"duration": 60,
"units": "mWh"
"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
],
},
}
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.
Here are example graphs made from this data, showing the year by the month, the month by the day, and the day by the hour:
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 modifier_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 | 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 |
modifier_annual_kwh | Modified annual consumption |
modifiers_monthly_kwh | Modified monthly consumption (array) |
Supply either annual or monthly modifiers, not both. For monthly modifiers, supported is 1 month or all 12 months.
Example request (POST data):
{
profile_id: 0,
usage: {
"duration": 60,
"units": "mWh"
"intervals": [
{
"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,
modifier_annual_kwh: null,
modifiers_monthly_kwh: [null, null, null, null, null, 500, null, null, null, null, null, null],
}
Example response (same as response from the load_profile API):
{
"success": true,
"message": "",
"usage": {
"net_kWh": 8261.55,
"annual_cost": 4108.19,
"duration": 60,
"units": "mWh"
"intervals": [
{
"start": "2024-01-01T00:00:00",
"pull": 709613,
"push": 0,
"net": 709613
},
... [ 8760 hourly values ] ...
],
"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
],
},
}
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 | Annual production to add (kWh) |
production_data | Hourly production data |
outlook_years | Years to calculate the savings outlook (25) |
cost_inflation_rate | Annual inflation rate for outlook (4%) |
Production Hourly Interval Data
For the solar production, you can either specify the annual kWh of production using production
and we will model the hourly data, or you can specify the specific hourly production using production_data
and we will use that.
The production_data
field specifies a year of hourly production data, where each hour specifies the start date/time, and the output. Like consumption, the duration is hourly, and the units are "mWh" (milliwatt-hours).
mwh = kwh * 10**6 // Move 6 decimal places
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: null,
production_data: [
{
"start": "2024-01-01T00:00:00",
"output": 709613,
},
... [ 8760 hourly values ] ...
],
outlook_years: 25,
cost_inflation_rate: 0.04,
}
Example response:
{
"success": true,
"message": "",
"savings": {
"average_bill": {
"bill_before": {
"usage": 686.64,
"base_fee": 0,
"usage_cost": 276.08,
"total": 276.08
},
"bill_after": {
"usage": 323.03,
"base_fee": 15,
"usage_cost": 121.25,
"total": 136.25
},
"savings": 139.83
},
"monthly_bills": [
{
"month": 1,
"month_name": "Jan",
"month_index": 4,
"bill_before": {
"usage": 753.09,
"base_fee": 0,
"usage_cost": 302.79,
"total": 302.79
},
"bill_after": {
"usage": 520.33,
"base_fee": 15,
"usage_cost": 189.91,
"total": 204.91
},
"savings": 97.88
},
... [ 12 months ] ...
],
"outlook": [
{
"year": 2025,
"year_index": 1,
"savings": 1678,
"cumulative_savings": 1678
},
... [ 25 years ] ...
]
}
}
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 (First Year)
The response contains monthly savings for the first year. This is returned both as an average month in average_bill
, or as 12 months in monthly_bills
. Each month contains the bill_before
($), the bill after bill_after
($), and the savings savings
($). Each bill has the usage
(kWh), the base fee base_fee
($), the usage cost usage_cost
($), and the total
($).
Savings Outlook
The savings outlook
is the savings over time using the inflation rate parameter cost_inflation_rate
(default is 4%). You specify how many years using the outlook_years
parameter (default is 25).
Here are example graphs made from these values, showing the monthly bill savings and the 25 year savings outlook: