openapi: 3.1.0 info: title: Gridshare Customer API description: | The Gridshare Customer API is the homeowner-delegated surface of Lunar Energy's Gridshare DERMS platform. It allows partners — apps, installers, retailers — to read or control devices on behalf of a specific Lunar Energy customer once that customer has granted consent via OAuth 2.0 Authorization Code flow against the lunar-customer Amazon Cognito user pool. Four scopes are available: `lunar/device.read`, `lunar/device.write`, `lunar/plan.read`, `lunar/plan.write`. 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.customer.mygridshare.com description: Production server - url: https://developer-api.customer.dev0.mygridshare.com description: Development server security: - bearerAuth: [] tags: - name: Sites description: List sites and read site topology - name: Devices description: List, get, and partially update customer devices - name: Telemetry description: Time-bucketed per-sensor telemetry readings - 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 paths: /api/v2/sites: get: operationId: listSites summary: List Sites description: | List the siteIds the authenticated customer has access to. v2 is the lightweight external endpoint — pair it with `GET /api/v2/sites/{siteId}/topology` and `GET /api/v2/devices` to drill into a site's structure or devices. tags: [Sites] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/SiteList' '401': { $ref: '#/components/responses/Unauthorized' } '403': { $ref: '#/components/responses/Forbidden' } /api/v2/sites/{siteId}/topology: parameters: - $ref: '#/components/parameters/SiteId' get: operationId: getSiteTopology summary: Get Site Topology description: | Return the electrical topology of a site the authenticated customer has access to. Nodes with `"kind": "sensor"` expose an `id` that may be passed to `GET /api/v2/devices/{synthId}/telemetry` and a `channels` array listing available streams. See the Topology key concepts page for worked examples. tags: [Sites] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Topology' '401': { $ref: '#/components/responses/Unauthorized' } '403': { $ref: '#/components/responses/Forbidden' } /api/v2/devices: get: operationId: listDevices summary: List Devices description: List all devices the authenticated customer has access to. tags: [Devices] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/DeviceList' '400': { $ref: '#/components/responses/Malformed' } '401': { $ref: '#/components/responses/Unauthorized' } '403': { $ref: '#/components/responses/Forbidden' } '422': { $ref: '#/components/responses/Unprocessable' } /api/v2/devices/{synthId}: parameters: - $ref: '#/components/parameters/SynthId' get: operationId: getDevice summary: Get Device description: Get a device by ID along with its static properties. tags: [Devices] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Device' patch: operationId: patchDevice summary: Partially Update Device description: Update a device. tags: [Devices] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Device' responses: '200': description: OK /api/v2/devices/{synthId}/telemetry: parameters: - $ref: '#/components/parameters/SynthId' get: operationId: getDeviceTelemetry summary: Get Device Telemetry description: | Time-bucketed telemetry for a single device sensor stream. `synthId` must be a **sensor ID** from the site topology — any node with `"kind": "sensor"`. On most installations telemetry streams are keyed by derived sensor IDs such as `__GRID_METER_DERIVED`, `__bb_agg`, and `__PV_DERIVED`. `energy_Wh_increment` and `energy_Wh_decrement` are populated only when `include=energy` (or `include=default,energy`): - `energy_Wh_increment` — lifetime cumulative energy flowing **into** the device (positive) - `energy_Wh_decrement` — lifetime cumulative energy flowing **out of** the device (negative) tags: [Telemetry] parameters: - in: query name: include schema: { type: string } - 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 } responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Telemetry' /api/v2/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 of 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/v2/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 components: securitySchemes: bearerAuth: type: oauth2 description: | OAuth 2.0 Authorization Code flow against the lunar-customer Amazon Cognito user pool. flows: authorizationCode: authorizationUrl: https://lunar-customer-prod-us-west-1.auth.us-west-1.amazoncognito.com/oauth2/authorize tokenUrl: https://lunar-customer-prod-us-west-1.auth.us-west-1.amazoncognito.com/oauth2/token refreshUrl: https://lunar-customer-prod-us-west-1.auth.us-west-1.amazoncognito.com/oauth2/token scopes: lunar/device.read: Read device metadata and telemetry (excluding plans) lunar/device.write: Modify devices including operation mode lunar/plan.read: Read existing device plans lunar/plan.write: Send plans to a device 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. 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' } Malformed: description: 400 Malformed Input content: application/json: schema: { $ref: '#/components/schemas/MalformedInputResponse' } Unprocessable: description: 422 Unprocessable content: application/json: schema: { $ref: '#/components/schemas/UnprocessableResponse' } schemas: 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 } kind: type: string enum: [inverter, battery_pack, PV, EV, meter, load_control_relay] siteId: { type: string } manufacturer: { type: string } model: { type: string } serialNumber: { type: string } 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' } 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 }