Authentication

All API requests require your organization's API key sent as an HTTP header:

X-API-Key: YOUR_API_KEY

Find your API key in Settings → API Key. Keep it secret — it identifies your organization.

POST /api/v1/ingest

POST /api/v1/ingest — Up to 500 readings per call

Push a batch of timestamped readings for one sensor.

Request body

{
  "sensor_id": 12,
  "readings": [
    {"value": 182.4, "timestamp": "2026-07-22T14:03:00Z"},
    {"value": 183.1, "timestamp": "2026-07-22T14:04:00Z"}
  ]
}

Response (202 Accepted)

{"accepted": 2, "sensor_id": 12}

POST /api/v1/ingest/simple

POST /api/v1/ingest/simple — Single reading, server timestamp

Simplest possible integration — one reading, server assigns the timestamp. Perfect for PLCs and basic gateways.

Request body

{"sensor_id": 12, "value": 182.4}

Response (202 Accepted)

{"accepted": 1, "sensor_id": 12, "timestamp": "2026-07-22T14:03:00"}

GET /api/v1/status

GET /api/v1/status

Verify your API key and check plan details.

{"status": "ok", "org": "Acme Industries", "plan": "growth", "assets": 12}

Code Examples

curl — simple ingest
curl -X POST https://www.rahaff.com/api/v1/ingest/simple \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sensor_id": 1, "value": 182.4}'
curl — batch ingest
curl -X POST https://www.rahaff.com/api/v1/ingest \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sensor_id": 1,
    "readings": [
      {"value": 182.4, "timestamp": "2026-07-22T14:00:00Z"},
      {"value": 183.1, "timestamp": "2026-07-22T14:01:00Z"}
    ]
  }'
Python — simple ingest
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://www.rahaff.com"

def push_reading(sensor_id, value):
    resp = requests.post(
        f"{BASE_URL}/api/v1/ingest/simple",
        headers={"X-API-Key": API_KEY},
        json={"sensor_id": sensor_id, "value": value}
    )
    resp.raise_for_status()
    return resp.json()

# Example: push a temperature reading
result = push_reading(sensor_id=1, value=182.4)
print(result)  # {"accepted": 1, "sensor_id": 1, ...}
Python — batch ingest (e.g. from a data logger)
from datetime import datetime, timedelta

def push_batch(sensor_id, readings):
    """readings: list of (datetime, float) tuples"""
    resp = requests.post(
        f"{BASE_URL}/api/v1/ingest",
        headers={"X-API-Key": API_KEY},
        json={
            "sensor_id": sensor_id,
            "readings": [
                {"value": v, "timestamp": ts.isoformat() + "Z"}
                for ts, v in readings
            ]
        }
    )
    resp.raise_for_status()
    return resp.json()

# Push last hour of readings from your historian
now = datetime.utcnow()
readings = [(now - timedelta(minutes=i), 180.0 + i * 0.1) for i in range(60)]
push_batch(sensor_id=1, readings=readings)
Node.js — simple ingest
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://www.rahaff.com';

async function pushReading(sensorId, value) {
  const res = await fetch(`${BASE_URL}/api/v1/ingest/simple`, {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ sensor_id: sensorId, value }),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// Example
pushReading(1, 182.4).then(console.log);

Rate Limits & Plan Limits

PlanAssetsSensorsAnalysis IntervalMax Batch Size
Starter52060 min500 readings
Growth2510015 min500 readings
EnterpriseUnlimitedUnlimited15 min500 readings

Need higher limits? Contact team@jannat.ai