Documentation
Everything you need to connect devices, browsers, and creative tools to Datanet. SDK install, auth, channels, presence, history, and limits — all in one place. Looking for something runnable? See the demos →
Projects & Setup
Everything on DataNet is organized into projects. A project is the primary unit of isolation — it has its own API keys, channels, usage counters, and team members. Projects belong to your account (tenant).
To create a project, sign in to the dashboard and click New Project. Give it a name. The platform assigns a project ID which scopes your channel namespace:
project.<project-id>.<your-channel>Seats
Seats control who on your team can access a project in the dashboard. From Project Members, invite collaborators by email and assign them a role. Each plan has a seat limit — see Plans & Limits below.
| Role | Can do |
|---|---|
owner | Full control — keys, channels, seats, and project settings |
editor | Create and manage keys and channels |
viewer | Read-only dashboard access |
Devices
Provisioned devices are installation clients you want to identify, monitor, and revoke independently: microcontrollers, sensors, kiosks, bridge machines, or production scripts. Create one from Devices in the dashboard. DataNet gives it an opaque ID and shows its credential once.
Exchange that credential for a JWT. The device ID and channel scope come from the provisioned record and cannot be supplied by the client:
POST /auth/token
{ "deviceKey": "dk_live_...", "clientId": "python-sdk" }Browser and general server traffic can keep using project API keys. Those connections do not consume device slots. One device credential permits one live connection.
Quickstart checklist
- Sign in and create a project from the dashboard.
- Create an API key for the project, scoped to the channels you need.
- Create your channels in the dashboard before publishing or subscribing.
- Exchange the API key for a JWT via
POST /auth/tokenon the gateway. - Open a WebSocket connection using the JWT as a subprotocol header.
- Subscribe to channels and start publishing.
API Keys
API keys are created per project and exchanged for short-lived gateway JWTs through POST /auth/token on the realtime gateway. Keys can include scoped publish and subscribe channel patterns, along with presence and history access.
- Sign in to the dashboard.
- Open Customer Dashboard → API Keys.
- Choose the target project, then create a key and optional channel scope.
- Copy the raw key immediately. Only the hashed form is stored after creation.
/auth/token endpoint directly. For public clients, prefer a backend token exchange that returns only the short-lived JWT to the browser. The web app's /api/stream/token route is a demo helper for the public stream, not a general SDK auth endpoint.Install the SDK
Install via the Arduino Library Manager. The library targets ESP32 and ESP8266.
- Open Arduino IDE → Sketch → Include Library → Manage Libraries.
- Search for DataNet and install it.
- Install ArduinoJson and WebSockets if not already present.
- Connect Wi-Fi before calling
connect().
#include <WiFi.h>
#include <DataNet.h>Connect
All shipped SDKs follow the same flow: exchange an API key or device credential for a short-lived JWT via /auth/token, then open a WebSocket to /ws using the JWT in the Sec-WebSocket-Protocol header.
#include <WiFi.h>
#include <DataNet.h>
const char* WIFI_SSID = "your-ssid";
const char* WIFI_PASSWORD = "your-password";
DataNet datanet("ak_your_key_here");
void setup() {
Serial.begin(115200);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) delay(500);
datanet.on("connect", [](const char* event, const char* info) {
Serial.println("connected");
});
datanet.on("error", [](const char* event, const char* info) {
Serial.println(info);
});
datanet.connect();
}
void loop() {
datanet.loop();
}Channels & Access
Channels are provisioned in the dashboard and stored as project topics. The gateway checks both the project and the key scope before allowing sub or pub.
Channel names are plain strings. Scoped keys use wildcard patterns over those strings, including slash-friendly patterns like sensors/* and installation/**. Legacy dotted-prefix patterns are still accepted.
channel_not_allowed. If the channel has not been created in the dashboard, the gateway returns channel_not_provisioned.Dashboard permissions are role-based:
| Action | Minimum role |
|---|---|
| Create project | Tenant editor |
| Create key or channel | Project editor |
| Invite seats | Project admin |
| Delete project or channel | Project admin or owner |
Subscribe
Register one or more handlers per channel. Subscriptions are replayed automatically after reconnect.
void onTemperature(const char* channel, JsonVariant data) {
float value = data["value"] | 0.0;
Serial.println(value);
}
datanet.subscribe("demo.scalar.temperature", onTemperature);Publish
Publish any JSON-serialisable payload to a provisioned channel. The gateway applies connection, topic, and project rate limits before fan-out.
StaticJsonDocument<128> doc;
doc["value"] = 23.4;
doc["unit"] = "C";
datanet.publish("demo.scalar.temperature", doc.as<JsonVariant>());
datanet.publishFloat("demo.scalar.temperature", "value", 23.4);
datanet.publishString("installation/status", "state", "ready");Examples
Runnable, copy-pasteable projects you can fork. The ones below are relevant to the Arduino / ESP32 tab; browse the full set across every platform in the datanet-examples repository.
Plans & Limits
Billing is installation-based, but the platform also enforces technical limits per project and per topic. Current defaults in the app are:
| Plan | Projects | Seats | History | Channels | Devices | Msg/s | Price |
|---|---|---|---|---|---|---|---|
| Free | 1 | 1 | 0, 1, or 7 days | 60 hard | 5 | 100 | Free |
| Artist | 3 | 1 | 0, 1, 7, 30, or 90 days | 240 hard | 25 | 2,000 | $19 / mo |
| Studio | 10 | 3 | 0, 1, 7, 30, 90, or 365 days | 600 hard | 100 | 8,000 | $49 / mo |
| Institutional | Custom | Custom | Custom, up to 365 days by default | 2,500 hard | 500 | 25,000 | Contact us |
Enforcement
Limits are enforced at the gateway in real time. Violations are logged as incidents and visible in the dashboard under your project.
| Limit | What happens when exceeded |
|---|---|
| Connection limit | WebSocket upgrade is rejected. Existing connections are unaffected. |
| Message rate | Gateway returns {"error":"rate_limited","retry_ms":10000} and drops the message. Back off and retry using the retry_ms value. |
| Channel limit | Channel creation is rejected. Existing channels remain active. |
| Seat limit | Dashboard invite is rejected until a seat is freed. |
| History retention | Messages older than the retention window are trimmed from the Redis Stream and not returned by /history. |
Signup & Billing
During the public beta, accounts can enter the platform in three ways: start on the Free plan, choose a paid Artist or Studio plan during signup, or redeem a promo code for temporary Artist or Studio access without adding card details.
| Flow | How it works | Notes |
|---|---|---|
| Free signup | Create the account first, land on Free, and upgrade later from Billing. | Default path. |
| Paid signup | Create the account, then continue to Stripe Checkout for Artist or Studio. | Checkout success is UX; the Stripe webhook is the source of truth. |
| Promo-code access | Redeem a promo code right after signup or later on the Billing page. | Promo codes currently grant temporary Artist or Studio access for 1, 3, or 6 months. |
Automatic self-serve free trials are not enabled by default right now. The temporary access model is promo-driven, while Stripe-backed subscriptions handle long-term paid access.
Presence & History
DataNet exposes both realtime presence and message history. Presence and gateway history require a JWT with the relevant scope; dashboard history queries use the signed-in web session instead.
| Surface | Route | Auth | Purpose |
|---|---|---|---|
| Gateway | GET /presence?channel=... | Bearer JWT | Channel occupancy and member IDs |
| Gateway | GET /whereNow?userId=...&projectId=... | Bearer JWT | Channels currently joined by one user/device |
| Gateway | GET /history?channel=...&limit=50 | Bearer JWT | Recent Redis-stream replay for a channel |
| Web app | GET /api/messages?channel=... | Session cookie | Persisted DB-backed history with JSON or CSV export |
The dashboard history API clamps the requested time range to the project's allowed retention window and supports paginated previews plus json or csv downloads.
API Reference
Gateway HTTP
| Method | Path | Purpose |
|---|---|---|
POST | /auth/token | Exchange API key for short-lived gateway JWT |
GET | /presence | Presence lookup for a channel |
GET | /whereNow | Active channels for one user/device within a project |
GET | /history | Recent gateway history replay |
GET | /health | Liveness probe |
curl examples
No SDK or install required. These examples work from any terminal against the live production gateway.
# Exchange API key for a short-lived JWT
curl -X POST https://api.datanet.art/auth/token \
-H 'content-type: application/json' \
-d '{"apiKey":"YOUR_API_KEY"}'
# Check channel presence (requires JWT)
curl 'https://api.datanet.art/presence?channel=your.channel' \
-H 'authorization: Bearer YOUR_JWT'
# Fetch channel history (requires JWT)
curl 'https://api.datanet.art/history?channel=your.channel&limit=50' \
-H 'authorization: Bearer YOUR_JWT'WebSocket
wss://ws.datanet.art/ws
Sec-WebSocket-Protocol: bearer, <jwt>
{"op":"sub","ch":"sensors/temperature"}
{"op":"unsub","ch":"sensors/temperature"}
{"op":"pub","ch":"sensors/temperature","d":{"value":23.4}}
{"op":"pub","ch":"lights/rigA/universe/1","bin":true,"b64":"AQID","ct":"binary/dmx","meta":{"universe":1}}
{"op":"hb"}The gateway responds with connected, sub_ack, unsub_ack, hb_ack, and error envelopes. Custom clients can also publish binary payloads by sending bin, b64,ct, and optional meta fields.
Binary payloads and metadata
Binary signals are delivered with protocol metadata, not as anonymous bytes. A binary subscriber receives the raw bytes plus channel, from, timestamp, contentType, bytes, and optional custom metadata. This is important for DMX, Art-Net, compact sensor frames, and bridges that need to route packets without hard-coding context in both the sender and receiver.
The canonical gateway fanout is a metadata-bearing JSON envelope sent as a text WebSocket frame. SDKs may still tolerate legacy raw binary frames, but those frames are fallback-only because they do not include channel, sender, timestamp, or content type metadata.
Arduino / ESP32
DataNet datanet(
const char* apiKey,
const char* apiUrl = "https://api.datanet.art",
const char* wsHost = "ws.datanet.art",
int wsPort = 443
);| Method | Returns | Description |
|---|---|---|
connect() | bool | Fetch JWT and open WSS connection |
loop() | void | Drive socket callbacks and heartbeat |
connected() | bool | Connection state |
subscribe(channel, handler) | void | Register void(const char*, JsonVariant) handler |
unsubscribe(channel) | void | Remove channel subscription |
publish(channel, payload) | bool | Send JsonVariant payload |
publishFloat(...) | bool | Publish single float field |
publishString(...) | bool | Publish single string field |
getLastTimestamp(channel) | uint64_t | Last received timestamp for that channel |
on(event, handler) | void | Lifecycle events: connect, disconnect, error |