API Access
Beta
The Connexa API is currently in Beta. It is available to all users, but endpoints, response fields and limits may change as we gather feedback, so it should not be relied upon for mission critical business logic.
The Connexa API lets you read your own devices, their historical telemetry and their alerts from your own scripts and applications. It is read-only and only ever returns data for devices on your account.
Base URL: https://cloud.connexa.com/public-api/v1
Get an API key
- Open your profile and scroll to the bottom of the page. The API Keys panel is below the billing section, under the View Billing Portal button.
- Click the + Generate Key button at the bottom of that panel, give the key a label that says what it is for (for example "Grafana dashboard"), and choose how long it should last.
- Copy the key immediately. It is shown only once and cannot be retrieved later. If you lose it, revoke it and generate a new one.
Keys look like cxa_live_ followed by random characters. Treat one like a password: keep it out of
source control, screenshots and client-side code.
Keys always expire
Every key has an expiry date. The default is 90 days, and you can choose 30 days, 90 days, 180 days or 1 year when you generate it. There is no option for a key that never expires.
- The expiry date is shown in the Expires column of your key list.
- After that date the API answers
403with a message that the key has expired. Generate a replacement before then, and update your integration to use it. - You can have up to 10 active keys, so a new key can run alongside the old one while you switch over.
- To stop a key working early, click Revoke. This takes effect immediately.
Make your first request
Send the key in an Authorization header.
curl -H "Authorization: Bearer cxa_live_YOUR_KEY" \
https://cloud.connexa.com/public-api/v1/devices
The response lists your devices, and each one includes a deviceId. Use it to read that device's
data. The device endpoints also need a deviceid header containing the same ID.
curl -H "Authorization: Bearer cxa_live_YOUR_KEY" \
-H "deviceid: YOUR_DEVICE_ID" \
"https://cloud.connexa.com/public-api/v1/devices/YOUR_DEVICE_ID/data?window=7d&limit=100"
Endpoints
| Request | Returns |
|---|---|
GET /devices |
Your devices (id, name, status). |
GET /devices/:deviceId |
Full detail for one device. |
GET /devices/:deviceId/data |
Historical telemetry, newest first. Add object= to filter to one metric type. |
GET /devices/:deviceId/data/:object |
The same telemetry, already filtered to one metric type. |
GET /devices/:deviceId/alerts |
Historical alerts, newest first. |
Choosing a time range
Data and alert requests take one of:
window=7dorwindow=30d, relative to now. The default is7d.startDateandendDatetogether, in ISO 8601 format such as2025-01-23T00:00:00.000Z. The range can be at most 366 days. If you send both, the explicit range wins.
Pages of results
Results come in pages. Use limit to set the page size (data: default 100, maximum 500; alerts:
default 50, maximum 200). Each response includes nextCursor. If it is a string, pass it back as
cursor= to fetch the next page, keeping every other parameter the same. When nextCursor is
null you have everything.
curl -H "Authorization: Bearer cxa_live_YOUR_KEY" -H "deviceid: YOUR_DEVICE_ID" \
"https://cloud.connexa.com/public-api/v1/devices/YOUR_DEVICE_ID/data?window=30d&limit=500"
# => { "success": true, "data": [ ... ], "nextCursor": "eyJ2Ijoi..." }
curl -H "Authorization: Bearer cxa_live_YOUR_KEY" -H "deviceid: YOUR_DEVICE_ID" \
"https://cloud.connexa.com/public-api/v1/devices/YOUR_DEVICE_ID/data?window=30d&limit=500&cursor=eyJ2Ijoi..."
Each record contains sampled_at, published_at, object, slave, event, data,
fw_version and cc_firmware.
Each device in /devices and /devices/:deviceId contains deviceId, deviceName,
deviceStatus, sparkStatus, chargeControllerModel, firmware, fw_version, loadState,
loadSetting, batteryVoltage, signalStrength, lastHeard, daytimeOnlyState, pauseAlerts,
alertResumeTime, tag1, tag2, tag3, siteId and siteName. Billing and account details are
never included.
Example: download a month of data (Python)
import requests
BASE = "https://cloud.connexa.com/public-api/v1"
KEY = "cxa_live_YOUR_KEY"
DEVICE = "YOUR_DEVICE_ID"
headers = {"Authorization": f"Bearer {KEY}", "deviceid": DEVICE}
params = {"window": "30d", "limit": 500}
records = []
while True:
r = requests.get(f"{BASE}/devices/{DEVICE}/data", headers=headers, params=params)
r.raise_for_status()
body = r.json()
records.extend(body["data"])
if not body["nextCursor"]:
break
params["cursor"] = body["nextCursor"]
print(len(records), "records")
Limits
- Device endpoints: 100 requests per 15 minutes per account.
- Signing in with a password (
POST /auth/token, an alternative to API keys): 10 requests per 15 minutes. Prefer an API key for anything automated.
Responses include X-RateLimit-Remaining and X-RateLimit-Reset headers. If you go over, you get
429 with a Retry-After header: wait that many seconds and try again. Asking for larger pages
(up to the maximum) uses fewer requests than many small ones.
Errors
Every error has the same shape. error is the standard HTTP reason and message says what went wrong:
{ "success": false, "status": 400, "error": "Bad Request",
"message": "limit must be a positive integer (max 500)." }
| Status | Meaning |
|---|---|
400 |
A parameter is missing or invalid; the message says which. |
403 |
The key is missing, invalid, revoked or expired, or the device is not on your account. |
404 |
The device or route does not exist. |
429 |
Rate limit reached; wait for Retry-After. |
500 |
Something went wrong on our side; try again shortly. |
Good practice
- Give each integration its own labelled key so you can revoke one without affecting the others.
- Rotate keys before they expire.
- If a key may have been exposed, revoke it and generate a new one straight away.