Tutorials
Send from Any Language

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/json
  • x-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

  1. Go to app.plexus.company (opens in a new tab)
  2. Click Add Device
  3. 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.sh

Tips

  • 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), and 5xx (retry with backoff).

Response Format

A successful request returns:

{
  "success": true,
  "count": 2,
  "persisted": true,
  "persistedCount": 2
}

Next Steps