API Reference
HTTP API

HTTP API Reference

Send telemetry data to Plexus using HTTP or WebSocket. The HTTP API works from any language or platform that can make POST requests.

Authentication

All requests require an API key in the x-api-key header:

x-api-key: plx_xxxxx

Get your API key from app.plexus.company (opens in a new tab) -> Settings -> Developer.

Send Data

POST https://app.plexus.company/api/ingest

{
  "source_id": "sensor-001",
  "points": [
    {
      "metric": "temperature",
      "value": 72.5,
      "timestamp": 1699900000.123,
      "tags": { "location": "lab" },
      "session_id": "test-001"
    }
  ]
}

The top-level source_id applies to all points in the request. Per-point source_id overrides the top-level default. At least one must be provided.

Top-Level Fields

FieldTypeRequiredDescription
source_idstringNo*Default source ID for all points in this request
pointsarrayYesArray of data points
sdkstringNoSDK identifier (e.g., "c/0.5.4", "python/0.4.0"). Set automatically by the SDKs

* Either the top-level or per-point source_id must be provided.

Point Fields

FieldTypeRequiredDescription
metricstringYesMetric name (e.g., temperature, motor.rpm)
valueanyYesSee supported value types below
timestampfloatNoUnix timestamp in seconds or milliseconds (auto-detected: values < 10^12 are treated as seconds). Defaults to server time
source_idstringNo*Your device/source identifier. Lowercase [a-z0-9][a-z0-9._-]*. Overrides top-level source_id
tagsobjectNoKey-value labels for filtering
session_idstringNoGroup data points into a session

Supported Value Types

TypeExampleUse Case
number72.5, -40, 3.14159Sensor readings (most common)
string"error", "idle", "running"Status, state, labels
booleantrue, falseOn/off, enabled/disabled
object{"x": 1.2, "y": 3.4, "z": 5.6}Vector data, structured readings
array[1.0, 2.0, 3.0, 4.0]Waveforms, multiple values

Sessions

Group related data for analysis and playback.

Create a Session

POST https://app.plexus.company/api/sessions

{
  "session_id": "test-001",
  "name": "Motor Test Run",
  "source_id": "sensor-001",
  "status": "active"
}

End a Session

PATCH https://app.plexus.company/api/sessions/{session_id}

{
  "status": "completed",
  "ended_at": "2024-01-15T10:30:00Z"
}

Code Examples

curl / Bash

#!/bin/bash
API_KEY="plx_xxxxx"
SOURCE_ID="sensor-001"
 
curl -X POST https://app.plexus.company/api/ingest \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"points\": [{
      \"metric\": \"temperature\",
      \"value\": 72.5,
      \"timestamp\": $(date +%s),
      \"source_id\": \"$SOURCE_ID\"
    }]
  }"

Python

import requests
import time
 
requests.post(
    "https://app.plexus.company/api/ingest",
    headers={"x-api-key": "plx_xxxxx"},
    json={
        "points": [{
            "metric": "temperature",
            "value": 72.5,
            "timestamp": time.time(),
            "source_id": "sensor-001"
        }]
    }
)

JavaScript

await fetch("https://app.plexus.company/api/ingest", {
  method: "POST",
  headers: {
    "x-api-key": "plx_xxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    points: [
      {
        metric: "temperature",
        value: 72.5,
        timestamp: Date.now() / 1000,
        source_id: "sensor-001",
      },
    ],
  }),
});

Go

package main
 
import (
    "bytes"
    "encoding/json"
    "net/http"
    "time"
)
 
func main() {
    points := map[string]interface{}{
        "points": []map[string]interface{}{{
            "metric":    "temperature",
            "value":     72.5,
            "timestamp": float64(time.Now().Unix()),
            "source_id": "sensor-001",
        }},
    }
 
    body, _ := json.Marshal(points)
    req, _ := http.NewRequest("POST", "https://app.plexus.company/api/ingest", bytes.NewBuffer(body))
    req.Header.Set("x-api-key", "plx_xxxxx")
    req.Header.Set("Content-Type", "application/json")
 
    http.DefaultClient.Do(req)
}

Arduino / ESP32

#include <WiFi.h>
#include <HTTPClient.h>
 
void sendToPlexus(const char* metric, float value) {
    HTTPClient http;
    http.begin("https://app.plexus.company/api/ingest");
    http.addHeader("Content-Type", "application/json");
    http.addHeader("x-api-key", "plx_xxxxx");
 
    String payload = "{\"points\":[{";
    payload += "\"metric\":\"" + String(metric) + "\",";
    payload += "\"value\":" + String(value) + ",";
    payload += "\"timestamp\":" + String(millis() / 1000.0) + ",";  // time since boot, not epoch — use NTP for wall-clock time
    payload += "\"source_id\":\"esp32-001\"";
    payload += "}]}";
 
    http.POST(payload);
    http.end();
}

Limits

LimitValue
Max points per request10,000
Max payload size5 MB

Requests exceeding these limits are rejected before processing.

Response Format

A successful ingest returns:

{
  "success": true,
  "count": 3,
  "persisted": true,
  "persistedCount": 3
}
FieldTypeDescription
successbooleanWhether the request was accepted
countnumberNumber of data points received
persistedbooleanWhether data was written to storage
persistedCountnumberNumber of data points persisted

Error Codes

StatusMeaning
200Success
400Bad request — check your JSON format and required fields
401Invalid or missing API key
402Billing limit exceeded — upgrade your plan or check usage
403API key lacks required permissions
404Resource not found
410Resource expired (e.g., pairing code)
413Payload too large — max 5 MB per request
429Rate limited — back off and retry
500Internal server error — retry with exponential backoff

WebSocket API

For real-time, UI-controlled streaming, devices connect via WebSocket to the PartyKit server. This is what plexus run uses under the hood.

Connection Flow

  1. Device connects to the PartyKit server
  2. Device sends a device_auth message with its API key and available sensors
  3. Server responds with authenticated
  4. Dashboard sends control messages (start_stream, stop_stream, etc.)
  5. Device streams telemetry messages back through the server to connected browsers

Message Types (Dashboard to Device)

TypeDescription
start_streamStart streaming sensor data
stop_streamStop streaming
start_sessionStart recording to a session
stop_sessionStop recording
configureConfigure a sensor (e.g., sample rate)
executeRun a command on the device
cancelCancel a running command
pingKeepalive request

Message Types (Device to Dashboard)

TypeDescription
telemetrySensor data points
session_startedConfirm session started
session_stoppedConfirm session stopped
outputCommand execution output
pongKeepalive response

Best Practices

  • Batch points — Send multiple points per request to reduce HTTP overhead (up to 10,000 per request).
  • Include timestamps — Always send accurate timestamps. The server defaults to receive time if omitted, which adds network latency to your data.
  • Use consistent source IDs — The same physical device should always use the same source_id.
  • Tag your data — Use tags for filtering in the dashboard (e.g., {"location": "lab", "unit": "A"}).
  • Use sessions — Group related data for easier analysis and playback.
  • Prefer the agent for real-time — For UI-controlled devices, use plexus run (WebSocket) instead of direct HTTP.

Next Steps