- Overview
- Join Program
- Join Conflict
- No Programs
- Code




{
"connect_session": "cos_6587fa4362341be5b524de3b",
"route": "programs",
"live_mode": true,
"actions": [
"BACK",
"CLOSE"
],
"data": {
"device_type": "BATTERY_STORAGE",
"tariff_connected": false,
"location": {
"timezone": "America/Denver",
"currency_code": "USD"
},
"programs": [
{
"operator": { "id": "opr_8587fa49c7e5297ccc6c57e5", "display_name": "Pick" },
"id": "vpr_6a1f8e375db9de605baadd46",
"display_name": "Community Powershare",
"url": "https://pick.com/programs/community-powershare",
"enrollment_state": "NOT_ENROLLED",
"managed": false,
"currency_code": "USD",
"estimate": {
"amount": 612,
"period": "YEAR",
"dispatch_events_per_month": 15
},
"terms": {
"rewards": [
{ "basis": "FIXED", "rate": 15, "period": "QUARTER" },
{ "basis": "DELIVERED_KWH", "rate": 0.35 }
],
"opt_out_policy": "ALLOWED",
"notice_days": 30
},
"enrollment": {
"join_days": 10,
"dispatch_test_required": true
}
},
{
"operator": { "id": "opr_9c2e1b55d1a8340aa1b23f77", "display_name": "PG&E" },
"id": "vpr_7b2f9d486ec0ef716cbbee57",
"display_name": "On-demand V2G",
"url": "https://pge.com/programs/on-demand-v2g",
"enrollment_state": "NOT_ENROLLED",
"managed": true,
"currency_code": "USD",
"estimate": {
"amount": 104,
"period": "MONTH",
"dispatch_events_per_month": 8
},
"terms": {
"rewards": [],
"opt_out_policy": "NOT_ALLOWED",
"notice_days": 30
},
"enrollment": {
"join_days": 14,
"dispatch_test_required": true
}
}
]
}
}
curl --request POST \
--url https://connect.flatpeak.com \
--header 'Content-Type: application/json' \
--data '{
"connect_session": "cos_6587fa4362341be5b524de3b",
"route": "programs",
"data": {
"program": {
"id": "vpr_6a1f8e375db9de605baadd46"
}
}
}'
{
"connect_session": "cos_6587fa4362341be5b524de3b",
"route": "session_redirect",
"live_mode": true,
"data": {
"redirect_type": "OPERATOR_SIGNUP",
"redirect_url": "https://pge.com/programs/on-demand-v2g/signup?program_id=vpr_7b2f9d486ec0ef716cbbee57&oem_id=oem_6a3a8dada72cd0a249ff9528&signup_reference=sur_6a7c0e2f9b4d1a3c5e8f7b6d"
}
}
Enrollment state
NOT_ENROLLED means the device has never enrolled in the program. Show any other enrollment_state as enrollment states describes.A device can be in one program at a time. If the user picks another, ask them to leave the current one first.Tariff connection
tariff_connected is false until the location has a connected tariff, and selecting a program before then returns action_invalid. A managed tariff can be selected without one, because the VPP operator supplies the tariff.One operator’s programs
When the session was created with anoperator_id, programs lists only that VPP operator’s programs the device is eligible for. An enrollment the device holds with another VPP operator is still listed, so the user can see and leave it.Managed tariffs
managed is true when the VPP operator runs the device and the program replaces the user’s tariff. List managed tariffs under their own heading, after the programs where the user keeps their tariff. Every program dispatches through VPP events, and a managed tariff also runs the device with plans.The user signs up for a managed tariff with the VPP operator, so selecting one creates no enrollment. Connect answers with session_redirect and redirect_type OPERATOR_SIGNUP. Open redirect_url in the system browser, unchanged, and close Connect. The VPP operator learns nothing about the device at this point, and enrollment_state stays NOT_ENROLLED.After signing up, the user comes back to your app by universal link with a new Connect session. Connect shows consent there, and the enrollment starts once the user allows it.Hosted Connect reads “Keep your tariff, earn from events” and “Switch to a managed tariff. The operator runs your battery. Replaces your tariff.” Its button is “Join” on a program; on a managed tariff it is “Continue with PG&E”, with the operator’s display_name.Estimates
estimate is what the user is told to expect. It is a projection and never binding. The copy follows managed:managed | Copy |
|---|---|
false | ”You earn 612 USD per year” |
true | ”Your bill drops by 104 USD per month” |
| Field | Description |
|---|---|
amount | Estimated amount for one period, in the program’s currency_code. |
period | Period the estimate covers: YEAR or MONTH. The VPP operator sets it per program. |
dispatch_events_per_month | Approximate number of dispatch events per month the estimate assumes. |
Terms
terms holds what binds the user and the VPP operator once the user has joined. Show it on the Join screen. The enrollment keeps a copy of the terms it joined with, and a later change to the program does not alter that copy.| Field | Description |
|---|---|
rewards | What the user is paid, in the program’s currency_code. Empty when the program pays no rewards, as a managed tariff may. |
opt_out_policy | Whether the user may skip an event. |
notice_days | Maximum number of days leaving may take once the user is enrolled. |
rewards:basis | rate is paid | Copy |
|---|---|---|
FIXED | Once per period: MONTH, QUARTER or YEAR | ”15 USD per quarter” |
EVENT | Per event the device delivers in full | ”1 USD per event delivered in full” |
DELIVERED_KWH | Per kWh delivered | ”0.35 USD per kWh delivered” |
COMMITTED_KWH | Per kWh of the device’s locked share of an event | ”0.20 USD per kWh committed” |
opt_out_policy | The user may skip an event |
|---|---|
ALLOWED | Always. |
ALLOWED_BEFORE_LOCK | Until the allocation locks at time_allocation_locks. Device shares are then fixed. |
NOT_ALLOWED | Never. |
Joining and leaving
| Field | Description |
|---|---|
enrollment.join_days | Maximum number of days enrollment may take after the user asks to join. |
enrollment.dispatch_test_required | true when the device must deliver a short TEST event before approval. |
terms.notice_days | Maximum number of days leaving may take once the user is enrolled. |
No programs
Whenprograms is empty, status is NONE_AVAILABLE, so show an empty state. When a program becomes available to the device, your backend receives device.update. See Events.Actions
| Action | Result |
|---|---|
BACK | Returns the previous page. If there is none, returns callback_url. |
CLOSE | Returns the callback_url set on the Connect session. |
Errors
| Error code | Description |
|---|---|
data_json_invalid | Data does not conform to the JSON schema. |
action_invalid | Action is not available on this route, or is not permitted in the current state, for example program selection while no tariff is connected. |

