Send Data from Any Language
Plexus uses a simple HTTP API. If your language can make a POST request, it can send data to Plexus. No SDK required.
The API
POST https://app.plexus.company/api/ingest
Headers:
Content-Type: application/jsonx-api-key: plx_xxxxx
Body:
{
"source_id": "my-device",
"points": [
{ "metric": "temperature", "value": 23.5 },
{ "metric": "humidity", "value": 61.2 }
]
}That's it. Every example below follows this pattern.
Get Your API Key
- Go to app.plexus.company (opens in a new tab)
- Click Add Device
- Copy the API key (starts with
plx_)
curl
The simplest way to test. Run this from any terminal:
curl -X POST https://app.plexus.company/api/ingest \
-H "Content-Type: application/json" \
-H "x-api-key: plx_xxxxx" \
-d '{
"source_id": "test-device",
"points": [
{ "metric": "temperature", "value": 23.5 },
{ "metric": "humidity", "value": 61.2 }
]
}'Python
import requests
import time
API_KEY = "plx_xxxxx"
SOURCE_ID = "python-device"
def send(metrics: dict):
requests.post(
"https://app.plexus.company/api/ingest",
headers={"x-api-key": API_KEY},
json={
"source_id": SOURCE_ID,
"points": [
{"metric": k, "value": v, "timestamp": time.time()}
for k, v in metrics.items()
],
},
)
# Send data
send({"temperature": 23.5, "humidity": 61.2, "pressure": 1013.0})Or use the full-featured agent: pip install plexus-agent — see Python Agent Quickstart.
JavaScript / TypeScript
Node.js
const API_KEY = "plx_xxxxx";
const SOURCE_ID = "node-device";
async function send(metrics) {
await fetch("https://app.plexus.company/api/ingest", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY,
},
body: JSON.stringify({
source_id: SOURCE_ID,
points: Object.entries(metrics).map(([metric, value]) => ({
metric,
value,
timestamp: Date.now() / 1000,
})),
}),
});
}
// Send data
await send({ temperature: 23.5, humidity: 61.2 });Deno
const API_KEY = "plx_xxxxx";
await fetch("https://app.plexus.company/api/ingest", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY,
},
body: JSON.stringify({
source_id: "deno-device",
points: [{ metric: "temperature", value: 23.5 }],
}),
});Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
const (
apiKey = "plx_xxxxx"
sourceID = "go-device"
endpoint = "https://app.plexus.company/api/ingest"
)
type Point struct {
Metric string `json:"metric"`
Value float64 `json:"value"`
Timestamp float64 `json:"timestamp"`
}
type Payload struct {
SourceID string `json:"source_id"`
Points []Point `json:"points"`
}
func send(metrics map[string]float64) error {
points := make([]Point, 0, len(metrics))
now := float64(time.Now().Unix())
for k, v := range metrics {
points = append(points, Point{Metric: k, Value: v, Timestamp: now})
}
body, _ := json.Marshal(Payload{SourceID: sourceID, Points: points})
req, _ := http.NewRequest("POST", endpoint, bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-api-key", apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("plexus: HTTP %d", resp.StatusCode)
}
return nil
}
func main() {
err := send(map[string]float64{
"temperature": 23.5,
"humidity": 61.2,
})
if err != nil {
fmt.Println("Error:", err)
}
}Rust
use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE};
use serde_json::json;
use std::time::{SystemTime, UNIX_EPOCH};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = "plx_xxxxx";
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_secs_f64();
let mut headers = HeaderMap::new();
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
headers.insert("x-api-key", HeaderValue::from_str(api_key)?);
let body = json!({
"source_id": "rust-device",
"points": [
{ "metric": "temperature", "value": 23.5, "timestamp": now },
{ "metric": "humidity", "value": 61.2, "timestamp": now }
]
});
let resp = reqwest::Client::new()
.post("https://app.plexus.company/api/ingest")
.headers(headers)
.json(&body)
.send()
.await?;
println!("Status: {}", resp.status());
Ok(())
}Cargo.toml dependencies:
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }Ruby
require 'net/http'
require 'json'
API_KEY = "plx_xxxxx"
SOURCE_ID = "ruby-device"
uri = URI("https://app.plexus.company/api/ingest")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["x-api-key"] = API_KEY
request.body = {
source_id: SOURCE_ID,
points: [
{ metric: "temperature", value: 23.5, timestamp: Time.now.to_f },
{ metric: "humidity", value: 61.2, timestamp: Time.now.to_f }
]
}.to_json
response = http.request(request)
puts "Status: #{response.code}"C# / .NET
using System.Net.Http.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "plx_xxxxx");
var payload = new {
source_id = "dotnet-device",
points = new[] {
new { metric = "temperature", value = 23.5, timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
new { metric = "humidity", value = 61.2, timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
}
};
var response = await client.PostAsJsonAsync(
"https://app.plexus.company/api/ingest", payload);
Console.WriteLine($"Status: {response.StatusCode}");Shell Script (Bash Loop)
Send data from a cron job or monitoring script:
#!/bin/bash
API_KEY="plx_xxxxx"
SOURCE_ID="server-001"
# Read system metrics
CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}')
MEM=$(free | awk '/Mem:/ {printf "%.1f", $3/$2 * 100}')
DISK=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
curl -s -X POST https://app.plexus.company/api/ingest \
-H "Content-Type: application/json" \
-H "x-api-key: $API_KEY" \
-d "{
\"source_id\": \"$SOURCE_ID\",
\"points\": [
{\"metric\": \"cpu_percent\", \"value\": $CPU},
{\"metric\": \"memory_percent\", \"value\": $MEM},
{\"metric\": \"disk_percent\", \"value\": $DISK}
]
}"Add to cron to run every minute:
* * * * * /path/to/send-metrics.shTips
- Batch your points — Send multiple metrics per request instead of one request per metric. Up to 10,000 points per request.
- Include timestamps — If you omit
timestamp, the server uses receive time. For accurate data, always include it. - Use consistent source IDs — The same device should always use the same
source_id. This is how Plexus groups metrics. - Add tags for filtering — Tags help you filter in the dashboard:
{"location": "lab", "version": "2.1"}. - Handle errors — Check for
401(bad API key),429(rate limited — back off), and5xx(retry with backoff).
Response Format
A successful request returns:
{
"success": true,
"count": 2,
"persisted": true,
"persistedCount": 2
}Next Steps
- HTTP API Reference — Full field reference, limits, and WebSocket API
- Python Agent — Full-featured agent with auto-detection, CLI, and adapters
- ESP32 / C SDK — Send from microcontrollers
- Core Concepts — Understand sources, metrics, tags, and sessions