{"openapi":"3.0.0","paths":{"/management/v1/organizations/mine":{"get":{"operationId":"OrganizationController_accountOrganizations","summary":"Get this account/user organizations","parameters":[],"responses":{"200":{"description":"returns a list of organizations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Organization"}}}}},"400":{"description":""}},"tags":["organization"],"security":[{"bluebot-api-key":[]},{"bearer":[]}]}},"/management/v1/version":{"get":{"operationId":"VersionController_getVersion","summary":"Get backend version","parameters":[],"responses":{"200":{"description":"returns the backend version","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionResponse"}}}}},"tags":["version"]}},"/management/v1/device":{"get":{"operationId":"DevicesController_getDevices","summary":"Get all Devices","parameters":[{"name":"limit","required":false,"in":"query","description":"item limit","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"item offset","schema":{"type":"number"}},{"name":"order","required":false,"in":"query","description":"order by","schema":{"type":"string"}},{"name":"orderBy","required":false,"in":"query","description":"column order by","schema":{"type":"string"}},{"name":"pagination","required":false,"in":"query","description":"Return paginated response with data and total count","schema":{"default":false,"type":"boolean"}},{"name":"serialNumber","required":false,"in":"query","description":"device serial number","schema":{"type":"string"}},{"name":"networkUniqueIdentifier","required":false,"in":"query","description":"device network identifier","schema":{"type":"string"}},{"name":"active","required":false,"in":"query","description":"Filter by active status. Omit or 'true' = active only (default); 'false' = inactive only; 'null' = no filter.","schema":{"enum":["true","false","null"],"type":"string"}}],"responses":{"200":{"description":"Returns devices. When ?pagination=true, returns { data, total }; otherwise returns Device[].","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedDeviceResponse"}}}}},"tags":["device"],"security":[{"bluebot-api-key":[]},{"bearer":[]}]}},"/management/v1/flow/datapoints/{id}":{"get":{"operationId":"FlowController_getDatapoints","summary":"Datapoints (or rolled-up aggregations) for one device.","description":"Use `resolution` to pick the bucket size: `raw` returns per-event rows; `1min`/`5min`/`10min`/`1hour` read pre-built continuous-aggregate views; `day`/`month` are time-bucketed on-demand over the `1hour` view; `total` returns a single aggregated row across the whole matched range. Larger buckets cost less. :id accepts a UUID, serial number, or networkUniqueIdentifier. Serial-number and networkUniqueIdentifier lookups are restricted to active devices; inactive devices can only be addressed by UUID.","parameters":[{"name":"id","required":true,"in":"path","description":"Device identifier. Accepts a UUID (matches any device, active or inactive), a serial number, or a networkUniqueIdentifier. When a serial number or networkUniqueIdentifier is supplied, only active devices are matched — inactive devices will not be found.","schema":{"type":"string"}},{"name":"resolution","required":true,"in":"query","description":"Bucket size. `raw` reads fix.device_datapoints_corrected (per-event rows); `1min`/`5min`/`10min`/`1hour` read the matching continuous-aggregate view; `day`/`month` are time-bucketed on-demand over the `1hour` view; `total` returns a single row aggregated across the whole matched range — its source table is picked from the requested range (`from`/`to`): the coarsest aggregate whose bucket fits the range, or `raw` for sub-minute ranges; defaults to `1hour` when the range is unbounded. All non-raw resolutions return the same column shape (`bucket` + avg/min/max/total columns).","schema":{"enum":["raw","1min","5min","10min","1hour","day","month","total"],"type":"string"}},{"name":"from","required":false,"in":"query","description":"Inclusive lower bound for the bucket/timestamp (ISO 8601).","schema":{"format":"date-time","example":"2026-04-01T00:00:00Z","type":"string"}},{"name":"to","required":false,"in":"query","description":"Inclusive upper bound for the bucket/timestamp (ISO 8601).","schema":{"format":"date-time","example":"2026-05-01T00:00:00Z","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size. Max 10000.","schema":{"minimum":1,"maximum":10000,"default":1000,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Number of rows to skip for offset pagination.","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"count","required":false,"in":"query","description":"When true, return only `{ resolution, count }` instead of datapoints.","schema":{"type":"boolean"}},{"name":"timezone","required":false,"in":"query","description":"IANA timezone (e.g. `America/Los_Angeles`). When set, bucket timestamps in the response are returned as wall-clock time in this zone, and `day`/`month` bucket boundaries align to it.","schema":{"example":"America/Los_Angeles","type":"string"}},{"name":"filter","required":false,"in":"query","description":"Repeatable filter expressed as `field:op:value`. Allowed operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`. Allowed fields (raw): `flowRate`, `flowAmount`, `flowDuration`, `quality`, `signalStrength`, `networkRssi`, `onboardTemperature`. Allowed fields (aggregated): same as raw minus `flowDuration`, plus `minFlowRate`, `maxFlowRate`, `minQuality`, `maxQuality`, `minSignalStrength`, `maxSignalStrength`, `minNetworkRssi`, `maxNetworkRssi`, `minOnboardTemperature`, `maxOnboardTemperature`. On aggregated views (including `day`/`month`/`total`, which scan the `1hour` source), the unprefixed name maps to the `avg_*` column.","schema":{"example":["quality:gte:0.5","flowRate:lt:100"],"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatapointsResponse"}}}}},"tags":["flow"],"security":[{"bluebot-api-key":[]},{"bearer":[]}]}},"/management/v1/flow/adaptive/{id}":{"get":{"operationId":"FlowController_getAdaptive","summary":"Highest resolution that fits within maxDatapoints for a range.","description":":id accepts a UUID, serial number, or networkUniqueIdentifier. Serial-number and networkUniqueIdentifier lookups are restricted to active devices; inactive devices can only be addressed by UUID.","parameters":[{"name":"id","required":true,"in":"path","description":"Device identifier. Accepts a UUID (matches any device, active or inactive), a serial number, or a networkUniqueIdentifier. When a serial number or networkUniqueIdentifier is supplied, only active devices are matched — inactive devices will not be found.","schema":{"type":"string"}},{"name":"from","required":true,"in":"query","description":"Inclusive lower bound for the range (ISO 8601).","schema":{"format":"date-time","example":"2026-04-01T00:00:00Z","type":"string"}},{"name":"to","required":true,"in":"query","description":"Inclusive upper bound for the range (ISO 8601).","schema":{"format":"date-time","example":"2026-05-01T00:00:00Z","type":"string"}},{"name":"maxDatapoints","required":false,"in":"query","description":"Maximum number of datapoints to return. The service walks 1hour → 10min → 5min → 1min → raw, stopping as soon as a resolution would exceed this cap, and returns data at the previous (highest-fidelity that still fits) resolution. Only touches the raw table when every aggregate already fit.","schema":{"minimum":1,"maximum":10000,"default":1000,"type":"number"}},{"name":"timezone","required":false,"in":"query","description":"IANA timezone (e.g. `America/Los_Angeles`). When set, bucket timestamps in the response are returned as wall-clock time in this zone.","schema":{"example":"America/Los_Angeles","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdaptiveResponse"}}}}},"tags":["flow"],"security":[{"bluebot-api-key":[]},{"bearer":[]}]}},"/management/v1/flow/latest":{"get":{"operationId":"FlowController_getLatest","summary":"Latest summary metrics (uptime, lastSeen, lastDatapoint, quality) for up to 50 devices.","description":"ids may mix UUIDs, serial numbers, and networkUniqueIdentifiers. Serial-number and networkUniqueIdentifier entries match only active devices; inactive devices must be addressed by UUID and will be omitted otherwise. `lastDatapoint` returns the most recent raw row (timestamp + sensor fields) within the range; `lastSeen` returns only that row’s timestamp.","parameters":[{"name":"ids","required":true,"in":"query","description":"Comma-separated list of device identifiers (UUIDs, serial numbers, or networkUniqueIdentifiers — may mix). Up to 50 entries.","schema":{"example":"BB1,BB2,8a4ff42a-5c14-4c8b-9a7e-3f9d4f5d6e7f","type":"string"}},{"name":"metrics","required":true,"in":"query","description":"Comma-separated list of metrics to compute per device. Any subset of `uptime`, `lastSeen`, `lastDatapoint`, `quality`. `lastDatapoint` returns the most recent raw row within the range (timestamp plus all sensor fields); `lastSeen` returns only that row’s timestamp.","schema":{"example":"uptime,lastSeen,lastDatapoint,quality","type":"array","items":{"type":"string","enum":["uptime","lastSeen","lastDatapoint","quality"]}}},{"name":"from","required":false,"in":"query","description":"Inclusive lower bound for the metric window (ISO 8601). Defaults to `to - 24h`.","schema":{"format":"date-time","example":"2026-05-01T00:00:00Z","type":"string"}},{"name":"to","required":false,"in":"query","description":"Inclusive upper bound for the metric window (ISO 8601). Defaults to now.","schema":{"format":"date-time","example":"2026-05-02T00:00:00Z","type":"string"}},{"name":"uptimeResolution","required":false,"in":"query","description":"Resolution used for the `uptime` metric. Must be aggregated; pass `1min` for sub-minute ranges. Determines the expected bucket count over the range.","schema":{"default":"1min","enum":["1min","5min","10min","1hour"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LatestResponse"}}}}},"tags":["flow"],"security":[{"bluebot-api-key":[]},{"bearer":[]}]}}},"info":{"title":"BlueBot API","description":"Bluebot API Documentation","version":"1.0.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"},"bluebot-api-key":{"type":"apiKey","in":"header","name":"bluebot-api-key"}},"schemas":{"Organization":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"created":{"format":"date-time","type":"string"},"updated":{"format":"date-time","type":"string"},"defaultCostPerGallon":{"type":"number"},"accountOrganizations":{"type":"object"},"subscriptions":{"type":"object"}},"required":["id","name","created"]},"VersionResponse":{"type":"object","properties":{"version":{"type":"string","description":"Version number as a string","default":"1.2.3"}},"required":["version"]},"i":{"type":"object","properties":{}},"Device":{"type":"object","properties":{"id":{"type":"string"},"category":{"type":"string","enum":["EndDevice","Gateway"]},"serialNumber":{"type":"string"},"created":{"format":"date-time","type":"string"},"updated":{"format":"date-time","type":"string"},"label":{"type":"string"},"installedOn":{"format":"date-time","type":"string"},"installed":{"type":"boolean"},"costPerGallon":{"$ref":"#/components/schemas/i"},"alertsActive":{"type":"boolean"},"kFactor":{"$ref":"#/components/schemas/i"},"deviceTimeZone":{"type":"string"},"model":{"type":"string"},"organizationId":{"type":"string"},"resellerId":{"type":"string"},"distributorId":{"type":"string"},"networkUniqueIdentifier":{"type":"string"},"billingSubscriptions":{"description":"Active billing subscriptions for this device","type":"array","items":{"type":"string"}}},"required":["id","category","serialNumber","created","updated","label","installedOn","installed","costPerGallon","alertsActive","kFactor","deviceTimeZone","model","networkUniqueIdentifier"]},"DevicePreviewResponse":{"type":"object","properties":{"preview":{"type":"object","additionalProperties":true,"nullable":true,"description":"Raw invoice preview returned by the billing engine. Null when the resolved activation target type is \"skip\" (no subscription would be created)."},"planKey":{"type":"string","nullable":true,"description":"The plan key that would be used to create the subscription. Null when no subscription would be created."},"billingInterval":{"type":"string","enum":["MONTHLY","ANNUAL"],"description":"Billing interval that would be used."},"additional":{"type":"object","additionalProperties":true,"nullable":true,"description":"Additional subscription parameters (prepaidTemplates, priceOverrides, metadata, etc.) that would be sent alongside planKey."},"plan":{"type":"object","additionalProperties":true,"nullable":true,"description":"Plan details from the billing engine (name, description, etc.). Null when no plan could be resolved."}},"required":["billingInterval"]},"TransferDeviceBillingStatus":{"type":"object","properties":{"sourceSubscriptionsCanceled":{"type":"boolean"},"targetSubscriptionCreated":{"type":"boolean"},"errors":{"type":"array","items":{"type":"string"}}},"required":["sourceSubscriptionsCanceled","targetSubscriptionCreated","errors"]},"TransferDeviceResponseDto":{"type":"object","properties":{"device":{"$ref":"#/components/schemas/Device"},"billing":{"$ref":"#/components/schemas/TransferDeviceBillingStatus"}},"required":["device","billing"]},"TransferDevicePreviewResponseDto":{"type":"object","properties":{"preview":{"type":"object"},"planKey":{"type":"string","nullable":true},"billingInterval":{"type":"string"},"additional":{"type":"object"},"plan":{"type":"object"},"sourceSubscription":{"type":"object"}},"required":["preview","planKey","billingInterval","additional","plan","sourceSubscription"]},"PaginatedDeviceResponse":{"type":"object","properties":{"data":{"description":"Array of items","type":"array","items":{"$ref":"#/components/schemas/Device"}},"total":{"type":"number","description":"Total number of items","example":42}},"required":["data","total"]},"DatapointsResponse":{"type":"object","properties":{"resolution":{"type":"string","enum":["raw","1min","5min","10min","1hour","day","month","total"],"description":"Resolution used to satisfy the request."},"timezone":{"type":"string","nullable":true,"description":"IANA timezone applied to bucket timestamps (if any)."},"limit":{"type":"number","description":"Page size echoed back. For `total` always 1."},"offset":{"type":"number","description":"Offset echoed back. For `total` always 0."},"data":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Datapoints. Columns vary by resolution: `raw` returns `recorded_at, flow_rate, flow_duration, flow_amount, quality, signal_strength, network_rssi, onboard_temperature`; `1min`/`5min`/`10min`/`1hour` return `bucket_<x>` plus avg/min/max/total columns for each metric; `day`/`month` return `bucket` plus the same agg columns (computed on-demand over the `1hour` view); `total` returns a single row of agg columns with no `bucket`. For derived resolutions: `total_flow_amount` is exact; `min_*`/`max_*` are exact; `avg_flow_rate` is the time-weighted throughput (`total_flow_amount` / bucket minutes); the other `avg_*` columns are an unweighted mean of the hourly means and are approximate."},"count":{"type":"number","description":"Row count (when `count=true`)."}},"required":["resolution"]},"AdaptiveResponse":{"type":"object","properties":{"resolution":{"type":"string","enum":["raw","1min","5min","10min","1hour","day","month","total"],"description":"Resolution chosen by the adaptive algorithm — the highest resolution whose row count fits within `maxDatapoints`."},"count":{"type":"number","description":"Total rows at the chosen resolution within the range."},"truncated":{"type":"boolean","description":"True only when even the lowest-fidelity (1hour) view exceeded `maxDatapoints` — the data is then capped."},"timezone":{"type":"string","nullable":true,"description":"IANA timezone applied to bucket timestamps (if any)."},"data":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Datapoints at the chosen resolution. See DatapointsResponse for column shapes."}},"required":["resolution","count","truncated","timezone","data"]},"LatestRange":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}},"required":["from","to"]},"LatestUptime":{"type":"object","properties":{"actual":{"type":"number","description":"Buckets observed at `uptimeResolution` within the range."},"expected":{"type":"number","description":"Total buckets the range covers at `uptimeResolution`."}},"required":["actual","expected"]},"LatestQuality":{"type":"object","properties":{"min":{"type":"number","nullable":true},"max":{"type":"number","nullable":true}},"required":["min","max"]},"LatestDatapoint":{"type":"object","properties":{"recordedAt":{"type":"string","format":"date-time"},"flowRate":{"type":"number","nullable":true},"flowDuration":{"type":"number","nullable":true},"flowAmount":{"type":"number","nullable":true},"quality":{"type":"number","nullable":true},"signalStrength":{"type":"number","nullable":true},"networkRssi":{"type":"number","nullable":true},"onboardTemperature":{"type":"number","nullable":true}},"required":["recordedAt","flowRate","flowDuration","flowAmount","quality","signalStrength","networkRssi","onboardTemperature"]},"LatestEntry":{"type":"object","properties":{"deviceId":{"type":"string","format":"uuid"},"serialNumber":{"type":"string"},"networkUniqueIdentifier":{"type":"string"},"lastSeen":{"type":"string","format":"date-time","nullable":true,"description":"Latest `recorded_at` for the device within the range (if `lastSeen` requested)."},"uptime":{"description":"Bucket-presence ratio (if `uptime` requested).","allOf":[{"$ref":"#/components/schemas/LatestUptime"}]},"quality":{"description":"Quality min/max (if `quality` requested).","allOf":[{"$ref":"#/components/schemas/LatestQuality"}]},"lastDatapoint":{"nullable":true,"description":"Most recent raw datapoint within the range (if `lastDatapoint` requested); null if no rows in the window.","allOf":[{"$ref":"#/components/schemas/LatestDatapoint"}]}},"required":["deviceId","serialNumber","networkUniqueIdentifier"]},"LatestResponse":{"type":"object","properties":{"range":{"description":"Resolved time window.","allOf":[{"$ref":"#/components/schemas/LatestRange"}]},"qualityResolution":{"type":"string","enum":["raw","1min","5min","10min","1hour","day","month","total"],"nullable":true,"description":"Resolution chosen for the quality metric (lowest-fidelity bucket that fits the range), or null if quality not requested."},"uptimeResolution":{"type":"string","enum":["raw","1min","5min","10min","1hour","day","month","total"],"nullable":true,"description":"Resolution used for uptime, or null if uptime not requested."},"expectedBuckets":{"type":"number","description":"Total expected buckets at `uptimeResolution` over the range (0 if uptime not requested)."},"data":{"type":"array","items":{"$ref":"#/components/schemas/LatestEntry"}}},"required":["range","qualityResolution","uptimeResolution","expectedBuckets","data"]}}}}