openapi: 3.1.0 info: title: Gridshare Partner API description: | The Gridshare Partner API is Lunar Energy's operator-facing surface for utilities, retailers, and DER aggregators managing residential distributed energy resources at fleet scale. Covers Sites, Devices, Telemetry, Operation Mode, Overlay Plans, Periodical Tariffs, Dynamic Tariffs, Flex Groups, Flex Events, Flex Dispatches, Prognoses with Diff Requests and Diff Orders, Counterfactuals, and on-site Visits. Authentication is OAuth 2.0 client-credentials against an Amazon Cognito user pool. Tokens expire after 1 hour and are sent as `Authorization: Bearer ` on every request. version: v1.0 contact: name: Lunar Energy url: https://www.gridshare.com email: developers@gridshare.com x-logo: url: https://www.lunarenergy.com/favicon.ico servers: - url: https://developer-api.partner.us.mygridshare.com description: Production server (US) - url: https://developer-api.partner.mygridshare.com description: Production server (Rest of World) - url: https://developer-api.partner.dev0.us.mygridshare.com description: Development server (US) - url: https://developer-api.partner.dev0.mygridshare.com description: Development server (Rest of World) security: - bearerAuth: [] tags: - name: Sites description: List, get, create, and replace sites in the partner fleet - name: Devices description: List, get, create, replace, and patch DER devices - name: Telemetry description: Retrieve time-bucketed device telemetry and counterfactuals - name: Operation Mode description: Read or change the Gridshare operation mode of a device - name: Plans description: Read or set overlay plans for short-term device dispatch - name: Periodical Tariffs description: Manage periodical (recurring) tariffs - name: Dynamic Tariffs description: Manage dynamic time-series tariffs with 7-day pagination - name: Flex Groups description: Define and manage groups of DERs participating in flex programs - name: Flex Events description: Schedule and update flex events for a flex group - name: Flex Dispatches description: Opt participants out of an active flex dispatch - name: Prognoses description: Forecasted aggregate power profiles for flex groups - name: Diff Requests description: Request and commit differential adjustments to a prognosis - name: Visits description: Record on-site visits for installation or service paths: /api/v1/sites: get: operationId: listSites summary: List Sites description: List all sites the authenticated partner can access. tags: [Sites] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/SiteList' '401': { $ref: '#/components/responses/Unauthorized' } '403': { $ref: '#/components/responses/Forbidden' } post: operationId: createSite summary: Create Site description: Create a new site in the partner fleet. tags: [Sites] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Site' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/Site' /api/v1/sites/{siteId}: parameters: - $ref: '#/components/parameters/SiteId' get: operationId: getSite summary: Get Site description: Get a site by ID. tags: [Sites] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Site' put: operationId: replaceSite summary: Replace Site description: Override a site with new attributes. tags: [Sites] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Site' responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Site' /api/v1/sites/{siteId}/topology: parameters: - $ref: '#/components/parameters/SiteId' get: operationId: getSiteTopology summary: Get Site Topology description: | Return the electrical topology tree of a site. Nodes with `"kind": "sensor"` expose an `id` that may be passed to the device telemetry endpoint and a `channels` array of available data streams. tags: [Sites] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Topology' /api/v1/devices: get: operationId: listDevices summary: List Devices description: List all devices in the partner fleet. tags: [Devices] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/DeviceList' post: operationId: createDevice summary: Create Device description: Create a new device. tags: [Devices] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Device' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/Device' /api/v1/devices/{synthId}: parameters: - $ref: '#/components/parameters/SynthId' get: operationId: getDevice summary: Get Device description: Get a device by ID with its static properties. tags: [Devices] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Device' put: operationId: replaceOrCreateDevice summary: Replace Or Create Device description: Override an existing device with new properties or create one if it does not yet exist. tags: [Devices] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Device' responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Device' /api/v1/devices/{synthId}/telemetry: parameters: - $ref: '#/components/parameters/SynthId' get: operationId: getDeviceTelemetry summary: Get Device Telemetry description: | Get time-bucketed telemetry for a device or sensor. `synthId` can be a device ID or a sensor ID from the site topology. Supported device kinds: `inverter`, `battery_pack`, `PV`, `EV`, `meter`, `load_control_relay`. Include `energy_Wh_increment` and `energy_Wh_decrement` by passing `include=default,energy`. tags: [Telemetry] parameters: - in: query name: include schema: { type: string } description: Comma-separated set of telemetry fields. `energy` is opt-in. - in: query name: start schema: { type: string, format: date-time } - in: query name: end schema: { type: string, format: date-time } - in: query name: bucket schema: { type: string } description: Time-bucket size (e.g. `PT1H`). responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Telemetry' /api/v1/devices/{synthId}/operationmode: parameters: - $ref: '#/components/parameters/SynthId' get: operationId: getDeviceOperationMode summary: Get Device Operation Mode description: | Get the current Gridshare operation mode of a device. Valid modes: - `Simple` — follow the simplest plan possible for the device kind - `Schedule` — follow a periodical plan - `Smart` — AI-optimized smart plan - `Unknown` — operation mode cannot be determined tags: [Operation Mode] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/OperationMode' put: operationId: setDeviceOperationMode summary: Change Device Operation Mode description: Set the Gridshare operation mode for a device. tags: [Operation Mode] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/OperationMode' responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/OperationMode' /api/v1/devices/{synthId}/plans/overlay: parameters: - $ref: '#/components/parameters/SynthId' get: operationId: getDeviceOverlayPlan summary: Get Device Overlay Plan description: Get the current overlay plan for the device. tags: [Plans] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/OverlayPlan' put: operationId: setDeviceOverlayPlan summary: Set Device Overlay Plan description: | Set an overlay plan for the device. To delete an overlay plan, send an empty `commands` array in the request body. tags: [Plans] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/OverlayPlan' responses: '200': description: OK /api/v1/periodicaltariffs: get: operationId: listPeriodicalTariffs summary: List Periodical Tariffs description: List all periodical tariffs. tags: [Periodical Tariffs] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/PeriodicalTariffList' post: operationId: createPeriodicalTariff summary: Create Periodical Tariff tags: [Periodical Tariffs] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PeriodicalTariff' responses: '201': description: Created /api/v1/periodicaltariffs/{tariffId}: parameters: - $ref: '#/components/parameters/TariffId' get: operationId: getPeriodicalTariff summary: Get Periodical Tariff tags: [Periodical Tariffs] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/PeriodicalTariff' patch: operationId: updatePeriodicalTariff summary: Update Periodical Tariff description: | Update properties of an existing periodical tariff. Append or rewrite pricing periods. Tariffs may have an open-ended latest period; PATCH-ing in a later period closes it automatically. tags: [Periodical Tariffs] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PeriodicalTariff' responses: '200': description: OK /api/v1/dynamictariffs: get: operationId: listDynamicTariffs summary: List Dynamic Tariffs description: List all dynamic tariffs for the calling partner account. tags: [Dynamic Tariffs] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/DynamicTariffList' post: operationId: createDynamicTariff summary: Create Dynamic Tariff description: Create a dynamic tariff with an optional initial set of timeseries values. tags: [Dynamic Tariffs] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DynamicTariff' responses: '201': description: Created /api/v1/dynamictariffs/{tariffId}: parameters: - $ref: '#/components/parameters/TariffId' get: operationId: getDynamicTariff summary: Get Dynamic Tariff description: | Return metadata for a dynamic tariff together with a single page of timeseries values covering a 7-day window. Paginate via `nextToken`. tags: [Dynamic Tariffs] parameters: - in: query name: interval schema: { type: string } - in: query name: nextToken schema: { type: string } responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/DynamicTariff' patch: operationId: updateDynamicTariff summary: Update Dynamic Tariff description: Append or override periods of a dynamic tariff. Existing values are not deleted. tags: [Dynamic Tariffs] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DynamicTariff' responses: '200': description: OK /api/v1/flexgroups: get: operationId: listFlexGroups summary: List Flex Groups tags: [Flex Groups] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/FlexGroupList' post: operationId: createFlexGroup summary: Create Flex Group tags: [Flex Groups] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FlexGroup' responses: '201': description: Created /api/v1/flexgroups/{flexGroupId}: parameters: - $ref: '#/components/parameters/FlexGroupId' get: operationId: getFlexGroup summary: Get Flex Group tags: [Flex Groups] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/FlexGroup' /api/v1/flexgroups/{flexGroupId}/participants: parameters: - $ref: '#/components/parameters/FlexGroupId' get: operationId: listFlexGroupParticipants summary: List Flex Group Participants tags: [Flex Groups] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/ParticipantList' post: operationId: addFlexGroupParticipant summary: Add Flex Group Participant tags: [Flex Groups] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Participant' responses: '201': description: Created /api/v1/flexgroups/{flexGroupId}/participants/{participantId}: parameters: - $ref: '#/components/parameters/FlexGroupId' - $ref: '#/components/parameters/ParticipantId' get: operationId: getFlexGroupParticipant summary: Get Flex Group Participant tags: [Flex Groups] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Participant' delete: operationId: deleteFlexGroupParticipant summary: Delete Flex Group Participant tags: [Flex Groups] responses: '204': description: Deleted /api/v1/flexgroups/{flexGroupId}/participants/bulk: parameters: - $ref: '#/components/parameters/FlexGroupId' post: operationId: createBulkParticipantsAction summary: Create Bulk Participants Action description: | Overwrite the participants of a flex group by sending a full replacement list. This action is irreversible. tags: [Flex Groups] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ParticipantList' responses: '202': description: Accepted /api/v1/flexgroups/{flexGroupId}/participants/bulk/{bulkId}: parameters: - $ref: '#/components/parameters/FlexGroupId' - in: path name: bulkId required: true schema: { type: string } get: operationId: getBulkParticipantsAction summary: Get Bulk Participants Action description: Retrieve the status of a bulk participants update. tags: [Flex Groups] responses: '200': description: OK /api/v1/flexevent: get: operationId: listFlexEvents summary: List Flex Events description: List all flex events within a time range, optionally filtered by group. tags: [Flex Events] parameters: - in: query name: start schema: { type: string, format: date-time } - in: query name: end schema: { type: string, format: date-time } - in: query name: flexGroupId schema: { type: string } responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/FlexEventList' post: operationId: createFlexEvent summary: Create Flex Event description: | Create a flex event for a defined flex group. Supports flat-dispatch events that target a flat power profile across a specified window. tags: [Flex Events] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FlexEvent' responses: '201': description: Created /api/v1/flexevents/{flexEventId}: parameters: - in: path name: flexEventId required: true schema: { type: string } patch: operationId: updateFlexEvent summary: Update Flex Event description: Update or cancel an existing flex event. tags: [Flex Events] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FlexEvent' responses: '200': description: OK /api/v1/flexdispatches/{flexDispatchId}/optout: parameters: - in: path name: flexDispatchId required: true schema: { type: string } post: operationId: optOutFlexDispatch summary: Opt Out Of Flex Dispatch description: | Opt a participant out of a flex dispatch. Participants may be identified by site ID or participant ID. Idempotent — repeat opt-outs return the original opt-out details. tags: [Flex Dispatches] requestBody: required: true content: application/json: schema: type: object properties: siteId: { type: string } participantId: { type: string } reason: { type: string } responses: '200': description: OK /api/v1/flexgroups/{flexGroupId}/prognoses: parameters: - $ref: '#/components/parameters/FlexGroupId' get: operationId: listPrognoses summary: List Prognoses description: | List prognoses for a specific flex group. A new prognosis is generated when the group forecast changes due to prediction updates or explicit flex actions. tags: [Prognoses] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/PrognosisList' /api/v1/prognoses/{prognosisId}/prognosisdiffrequests: parameters: - in: path name: prognosisId required: true schema: { type: string } post: operationId: createPrognosisDiffRequest summary: Create Prognosis Diff Request description: | Request a modification to a prognosis profile. Allows charging or discharging to the network in a coordinated manner by submitting a differential profile over the original prognosis. Asynchronous — poll the Diff Request endpoint for status. tags: [Diff Requests] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PrognosisDiffRequest' responses: '202': description: Accepted /api/v1/prognosisdiffrequests/{prognosisDiffRequestId}: parameters: - in: path name: prognosisDiffRequestId required: true schema: { type: string } get: operationId: getPrognosisDiffRequest summary: Get Prognosis Diff Request description: Poll status and feasible offer for a prognosis diff request. tags: [Diff Requests] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/PrognosisDiffRequest' /api/v1/prognosisdiffrequests/{prognosisDiffRequestId}/prognosisdifforders: parameters: - in: path name: prognosisDiffRequestId required: true schema: { type: string } post: operationId: createPrognosisDiffOrder summary: Create Prognosis Diff Order description: | Confirm and commit to the offer associated with a prognosis diff request. Commands are dispatched to the underlying devices. tags: [Diff Requests] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PrognosisDiffOrder' responses: '201': description: Created /api/v1/prognosisdifforders/{prognosisDiffOrderId}: parameters: - in: path name: prognosisDiffOrderId required: true schema: { type: string } get: operationId: getPrognosisDiffOrder summary: Get Prognosis Diff Order description: Retrieve a committed flex offer order including price and power profile. tags: [Diff Requests] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/PrognosisDiffOrder' /api/v1/counterfactuals/{counterfactualName}/devices/{deviceId}/telemetry: parameters: - in: path name: counterfactualName required: true schema: { type: string } - in: path name: deviceId required: true schema: { type: string } get: operationId: getCounterfactualTelemetry summary: Get Counterfactual Telemetry description: | Counterfactual telemetry — what the device would have done if it had not been smartly controlled. Availability depends on the counterfactuals enabled for your partner account. tags: [Telemetry] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Telemetry' /api/v1/visits: get: operationId: listVisits summary: List Visits tags: [Visits] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/VisitList' post: operationId: createVisit summary: Create Visit tags: [Visits] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Visit' responses: '201': description: Created /api/v1/visits/{visitId}: parameters: - in: path name: visitId required: true schema: { type: string } get: operationId: getVisit summary: Get Visit tags: [Visits] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Visit' components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: | OAuth 2.0 client-credentials access token obtained from the Gridshare partner Cognito authentication endpoint. parameters: SiteId: in: path name: siteId required: true schema: { type: string } SynthId: in: path name: synthId required: true schema: { type: string } description: A device ID or a sensor ID from the site topology. TariffId: in: path name: tariffId required: true schema: { type: string } FlexGroupId: in: path name: flexGroupId required: true schema: { type: string } ParticipantId: in: path name: participantId required: true schema: { type: string } responses: Unauthorized: description: 401 Unauthorized content: application/json: schema: { $ref: '#/components/schemas/UnauthorizedResponse' } Forbidden: description: 403 Forbidden content: application/json: schema: { $ref: '#/components/schemas/ForbiddenResponse' } schemas: Site: type: object required: [siteId] properties: siteId: { type: string } name: { type: string } timezone: { type: string } address: type: object properties: country: { type: string } region: { type: string } city: { type: string } postalCode: { type: string } line1: { type: string } SiteListItem: type: object required: [siteId] properties: siteId: { type: string } SiteList: type: object required: [entries] properties: entries: type: array items: { $ref: '#/components/schemas/SiteListItem' } TopologyNode: type: object properties: id: { type: string } kind: type: string enum: [site, device, sensor] channels: type: array items: { type: string } children: type: array items: { $ref: '#/components/schemas/TopologyNode' } Topology: type: object properties: root: { $ref: '#/components/schemas/TopologyNode' } Device: type: object required: [synthId] properties: synthId: { type: string } deviceId: { type: string } kind: type: string enum: [inverter, battery_pack, PV, EV, meter, load_control_relay] type: { type: string } siteId: { type: string } manufacturer: { type: string } model: { type: string } serialNumber: { type: string } properties: type: object additionalProperties: true DeviceListItem: type: object required: [synthId] properties: synthId: { type: string } DeviceList: type: object required: [entries] properties: entries: type: array items: { $ref: '#/components/schemas/DeviceListItem' } Telemetry: type: object properties: entries: type: array items: type: object properties: timestamp: { type: string, format: date-time } power_W: { type: number } voltage_V: { type: number } current_A: { type: number } stateOfCharge_pct: { type: number } energy_Wh_increment: { type: number } energy_Wh_decrement: { type: number } OperationMode: type: object required: [mode] properties: mode: type: string enum: [Simple, Schedule, Smart, Unknown] OverlayPlanCommand: type: object properties: start: { type: string, format: date-time } end: { type: string, format: date-time } action: type: string enum: [charge, discharge, hold, follow] powerLimit_W: { type: number } OverlayPlan: type: object required: [commands] properties: commands: type: array items: { $ref: '#/components/schemas/OverlayPlanCommand' } TariffExceptionPeriod: type: object properties: start: { type: string, format: date } end: { type: string, format: date } rate: { type: number } PricingPeriod: type: object properties: start: { type: string, format: date } end: { type: string, format: date } rates: type: array items: type: object properties: dayOfWeek: { type: string } from: { type: string } to: { type: string } price: { type: number } exceptions: type: array items: { $ref: '#/components/schemas/TariffExceptionPeriod' } PeriodicalTariff: type: object required: [name, companyName] properties: tariffId: { type: string } name: { type: string } companyName: { type: string } currency: { type: string } pricingPeriods: type: array items: { $ref: '#/components/schemas/PricingPeriod' } PeriodicalTariffList: type: object properties: entries: type: array items: { $ref: '#/components/schemas/PeriodicalTariff' } DynamicTariffValue: type: object properties: timestamp: { type: string, format: date-time } price: { type: number } DynamicTariff: type: object properties: tariffId: { type: string } name: { type: string } currency: { type: string } values: type: array items: { $ref: '#/components/schemas/DynamicTariffValue' } nextToken: { type: string } DynamicTariffList: type: object properties: entries: type: array items: { $ref: '#/components/schemas/DynamicTariff' } Participant: type: object properties: participantId: { type: string } siteId: { type: string } deviceIds: type: array items: { type: string } ParticipantList: type: object properties: entries: type: array items: { $ref: '#/components/schemas/Participant' } FlexGroup: type: object properties: flexGroupId: { type: string } name: { type: string } description: { type: string } settlementPoint: { type: string } FlexGroupList: type: object properties: entries: type: array items: { $ref: '#/components/schemas/FlexGroup' } FlexEvent: type: object properties: flexEventId: { type: string } flexGroupId: { type: string } type: type: string enum: [flatDispatch, ramp] start: { type: string, format: date-time } end: { type: string, format: date-time } powerProfile_W: { type: number } status: type: string enum: [pending, scheduled, active, completed, cancelled] FlexEventList: type: object properties: entries: type: array items: { $ref: '#/components/schemas/FlexEvent' } Prognosis: type: object properties: prognosisId: { type: string } flexGroupId: { type: string } generatedAt: { type: string, format: date-time } intervals: type: array items: type: object properties: start: { type: string, format: date-time } end: { type: string, format: date-time } power_W: { type: number } PrognosisList: type: object properties: entries: type: array items: { $ref: '#/components/schemas/Prognosis' } PrognosisDiffRequest: type: object properties: prognosisDiffRequestId: { type: string } prognosisId: { type: string } diffProfile: type: array items: type: object properties: start: { type: string, format: date-time } end: { type: string, format: date-time } deltaPower_W: { type: number } status: type: string enum: [pending, offered, expired, rejected, committed] offer: type: object properties: feasiblePower_W: { type: number } price: { type: number } currency: { type: string } PrognosisDiffOrder: type: object properties: prognosisDiffOrderId: { type: string } prognosisDiffRequestId: { type: string } acceptedAt: { type: string, format: date-time } powerProfile: type: array items: type: object properties: start: { type: string, format: date-time } end: { type: string, format: date-time } power_W: { type: number } price: { type: number } currency: { type: string } Visit: type: object properties: visitId: { type: string } siteId: { type: string } type: { type: string } scheduledAt: { type: string, format: date-time } completedAt: { type: string, format: date-time } notes: { type: string } VisitList: type: object properties: entries: type: array items: { $ref: '#/components/schemas/Visit' } ForbiddenResponse: type: object properties: message: { type: string } code: { type: string } MalformedInputResponse: type: object properties: message: { type: string } code: { type: string } UnauthorizedResponse: type: object properties: message: { type: string } code: { type: string } UnprocessableResponse: type: object properties: message: { type: string } code: { type: string }