This skill should be used when the user needs to integrate with Hubble Network Platform API for IoT device management, packet data retrieval, webhook configuration, metrics tracking, user management,...
Hubble Network connects off-the-shelf Bluetooth chips to a global network of 90M+ gateways. This skill covers integration with the Hubble Cloud API for device management, packet retrieval, webhooks, metrics, and organization administration.
https://api.hubble.comDevice โ a Bluetooth hardware endpoint registered on Hubble. Identified by a UUID (device.id), with encryption keys and custom/platform tags.
Packet โ Base64-encoded Bluetooth data received via gateways. Includes encrypted payload, sequence numbers, auth tags, and metadata (RSSI, SNR, gateway info, timestamps).
Webhook โ an HTTP endpoint that receives real-time packet batches via push. Configurable batch size (10โ1000), automatic retries, delivery metrics.
Organization โ top-level container (UUID) for devices, users, API keys, webhooks, billing.
API Key โ JWT bearer token with granular scopes.
Send the JWT bearer token in the Authorization header on every request:
Authorization: Bearer <jwt-token>
Generate tokens from Hubble Dashboard โ Developer โ API Tokens. Tokens cannot be retrieved after creation โ store them in a secret manager or environment variable.
Scopes follow the <resource>:<read|write> pattern across 8 resources: devices, packets, webhooks, organization, users, invitations, api_keys, metrics, plus billing:read. Apply least privilege โ request only the scopes a given integration needs. For the complete scope catalog with descriptions, see references/api-reference.md ("API Key Management").
Retry-After headerResponse headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) expose current state. On 429, honor Retry-After and back off exponentially. Prefer batch endpoints and webhook push over polling to stay under limits.
For request/response schemas and every parameter, see references/api-reference.md. For step-by-step implementation guides, see references/workflows.md. For runnable Python examples, see references/examples.md.
POST /api/v2/org/{org_id}/devices โ batch register (up to 1,000/request)GET /api/org/{org_id}/devices โ list with filtering/sortingGET /api/org/{org_id}/devices/{device_id} โ retrieve onePATCH /api/org/{org_id}/devices/{device_id} โ update onePATCH /api/org/{org_id}/devices โ batch update (up to 1,000)DELETE /api/org/{org_id}/devices โ batch delete (up to 1,000)Registration auto-generates device IDs and encryption keys. Encryption options: AES-256-CTR, AES-128-CTR, NONE.
GET /api/org/{org_id}/packets โ stream with continuation-token paginationParameters: start_time, end_time (default last 7 days), device_id, platform_tag (e.g. hubnet.platform=LoRaWAN).
POST /api/org/{org_id}/webhooks โ register endpointGET /api/org/{org_id}/webhooks โ listPATCH /api/org/{org_id}/webhooks/{webhook_id} โ updateDELETE /api/org/{org_id}/webhooks/{webhook_id} โ removeConfigure URL, display name, and max batch size (10โ1000; default 100).
GET /api/org/{org_id}/api_metrics โ API request metrics (hourly)GET /api/org/{org_id}/packet_metrics โ packet volumeGET /api/org/{org_id}/webhook_metrics โ delivery success/failureGET /api/org/{org_id}/device_metrics โ active/registered countsConfigurable days_back (1โ365) and interval (hour/day/month).
GET|PATCH /api/org/{org_id} โ read/update orgGET|POST /api/org/{org_id}/users, PATCH|DELETE .../{user_id} โ manage users (roles: Admin, Member)GET|POST|DELETE /api/org/{org_id}/invitations โ manage invitesGET /api/org/{org_id}/check โ validate current keyGET|POST /api/org/{org_id}/key, PATCH|DELETE .../{key_id} โ manage keysGET /api/org/{org_id}/key_scopes โ list available scopesGET /api/org/{org_id}/billing/invoices โ list invoicesGET /api/org/{org_id}/billing/invoices/{invoice_id}/pdf โ download PDFGET /api/org/{org_id}/billing/usage โ device usageThe packets endpoint returns a nested structure. Field locations differ from what naive callers expect, and getting them wrong is the most common integration bug.
{
"location": {
"timestamp": 1765598212.181298,
"latitude": 47.61421,
"longitude": -122.31929,
"altitude": 829,
"horizontal_accuracy": 29,
"vertical_accuracy": 29
},
"device": {
"id": "bc17a947-7a4f-4cff-9127-340cc4005272",
"name": "Device Display Name",
"tags": ["tag1", "tag2"],
"payload": "SGVsbG8gV29ybGQ=",
"timestamp": "2025-01-15T10:30:45Z",
"rssi": -85,
"sequence_number": 42,
"counter": 123
},
"network_type": "bluetooth"
}
Field locations:
packet.device.id โ not packet.device_id or packet.dev_euipacket.device.namepacket.device.rssi โ not packet.rssipacket.device.sequence_numberpacket.location.latitude, packet.location.longitudepacket.location.timestamp โ Unix epoch seconds (multiply by 1000 for JS Date)Large-dataset endpoints (notably /packets) use the Continuation-Token header, not offset/cursor query params:
Continuation-Token response header. If absent, streaming is complete.Continuation-Token: <value> set in request headers.For a complete streaming loop implementation, see references/examples.md ("Packet Retrieval Examples").
Binary data crosses JSON as Base64: device encryption keys on registration, and packet payloads on retrieval. A missing/bad Base64 encoding on device keys produces a 400 with "Invalid deviceKey format". Decode payloads with the standard library (base64.b64decode / Buffer.from(s, 'base64')).
Hubble POSTs JSON batches to the configured URL. Every request carries an HTTP-X-HUBBLE-TOKEN header โ validate it against the webhook secret before processing, and return 2xx only on successful receipt (any non-2xx triggers automatic retry with exponential backoff).
Request body shape:
{ "packets": [ { "device_id": "...", "payload": "...", "timestamp": "...", "metadata": { } } ] }
For a Flask/Express receiver with signature validation, see references/examples.md ("Webhook Examples"). For delivery-failure debugging, see references/troubleshooting.md ("Webhook Problems").
| Status | Meaning | Action |
|---|---|---|
| 200/201 | Success | โ |
| 400 | Bad request | Check payload shape; common: unencoded device key |
| 401 | Missing/invalid token | Verify Bearer prefix and token validity |
| 403 | Insufficient scope | Check key's scopes; confirm org ID |
| 404 | Not found | Validate IDs |
| 429 | Rate limited | Honor Retry-After, back off |
| 500 | Server error | Retry with backoff |
Every response includes an X-Request-ID header โ capture it in logs and include it in support requests. For full error catalog and fixes, see references/troubleshooting.md.
Validate the API key and its scopes:
curl -H "Authorization: Bearer $HUBBLE_API_TOKEN" \
https://api.hubble.com/api/org/$HUBBLE_ORG_ID/check
curl -H "Authorization: Bearer $HUBBLE_API_TOKEN" \
https://api.hubble.com/api/org/$HUBBLE_ORG_ID/key_scopes
X-Request-ID on every request for traceability.references/api-reference.md โ every endpoint with parameters, responses, and examplesreferences/workflows.md โ multi-step guides (device onboarding, packet streaming, webhook setup, key rotation, batch operations)references/examples.md โ runnable Python code for auth, device management, packets, webhooks, metricsreferences/troubleshooting.md โ symptom-indexed fixes for auth, registration, pagination, Base64, rate-limit, and webhook issuesresources/hubble-openapi.yaml โ machine-readable OpenAPI spec