Overview
DriftMind is a cold-start, self-adaptive forecasting engine designed for fast data environments. You create a forecaster, feed time-aligned observations, then request forecasts and anomaly scores.
What Swagger is for
Contract reference: endpoints, schemas, status codes, examples.
What this guide is for
Workflow, best practices, and runnable examples (Java + Python + curl).
Authentication
All requests require an API token passed via the Auth header:
Auth: <YOUR_API_TOKEN>
Environment setup
export DRIFTMIND_TOKEN="your-token-here"
$Env:DRIFTMIND_TOKEN="your-token-here"
Quickstart
The golden path is: Create → Feed → Predict → Delete. The snippet below runs the full cycle end-to-end.
FORECAST_NOT_READY if
insufficient data has been fed.
In that case, feed additional observations and retry.
import os, requests, time
BASE_URL = "https://api.thingbook.io/access/api/driftmind/v1"
headers = {"Auth": os.environ["DRIFTMIND_TOKEN"], "Content-Type": "application/json"}
# 1. Create
r = requests.post(f"{BASE_URL}/forecasters", headers=headers, json={
"forecasterName": "My First Forecaster",
"features": ["temperature", "humidity"],
"inputSize": 30,
"outputSize": 1
})
r.raise_for_status()
fid = r.json()["forecasterId"]
print("Created:", fid)
# 2. Feed — send enough observations to satisfy inputSize
observations = {
"temperature": [18.0 + i * 0.1 for i in range(35)],
"humidity": [0.60 + i * 0.002 for i in range(35)]
}
r = requests.post(f"{BASE_URL}/forecasters/{fid}/observations", headers=headers, json=observations)
r.raise_for_status()
print("Fed observations")
# 3. Predict
r = requests.get(f"{BASE_URL}/forecasters/{fid}/predictions", headers=headers)
r.raise_for_status()
result = r.json()
print(f"Anomaly score: {result['anomalyScore']}")
print(f"Temperature forecast: {result['features']['temperature']['predictions']}")
# 4. Delete
r = requests.delete(f"{BASE_URL}/forecasters/{fid}", headers=headers)
r.raise_for_status()
print("Deleted")
# 1. Create — save the returned forecasterId
FID=$(curl -s -X POST https://api.thingbook.io/access/api/driftmind/v1/forecasters \
-H "Auth: $DRIFTMIND_TOKEN" -H "Content-Type: application/json" \
-d '{"forecasterName":"My First Forecaster","features":["temperature","humidity"],"inputSize":30,"outputSize":1}' \
| grep -o '"forecasterId":"[^"]*"' | cut -d'"' -f4)
echo "Created: $FID"
# 2. Feed
curl -s -X POST https://api.thingbook.io/access/api/driftmind/v1/forecasters/$FID/observations \
-H "Auth: $DRIFTMIND_TOKEN" -H "Content-Type: application/json" \
-d '{"temperature":[18.0,18.1,18.2,18.3,18.4,18.5,18.6,18.7,18.8,18.9,19.0,19.1,19.2,19.3,19.4,19.5,19.6,19.7,19.8,19.9,20.0,20.1,20.2,20.3,20.4,20.5,20.6,20.7,20.8,20.9,21.0,21.1,21.2,21.3,21.4],"humidity":[0.60,0.60,0.61,0.61,0.62,0.62,0.60,0.59,0.58,0.60,0.61,0.62,0.60,0.59,0.61,0.62,0.63,0.60,0.59,0.58,0.60,0.61,0.62,0.63,0.60,0.61,0.62,0.59,0.58,0.60,0.61,0.62,0.63,0.60,0.59]}'
# 3. Predict
curl -s -X GET https://api.thingbook.io/access/api/driftmind/v1/forecasters/$FID/predictions \
-H "Auth: $DRIFTMIND_TOKEN"
# 4. Delete
curl -s -X DELETE https://api.thingbook.io/access/api/driftmind/v1/forecasters/$FID \
-H "Auth: $DRIFTMIND_TOKEN"
Create a Forecaster
Creates a multivariate forecaster and returns a forecasterId.
POST /driftmind/v1/forecasters
| Field | Description |
|---|---|
forecasterName |
Human-readable label for this forecaster. |
features |
Array of feature names. Each name must match the keys you send in observation payloads. |
inputSize |
Sliding window size — the number of past observations the model uses to generate each forecast. Larger values capture longer patterns but require more data before the first prediction is ready. |
outputSize |
Number of future time steps to forecast. Use 1 for single-step prediction or a higher value for a multi-step horizon. |
curl
curl -X POST https://api.thingbook.io/access/api/driftmind/v1/forecasters \
-H "Auth: $DRIFTMIND_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"forecasterName": "Temperature Forecaster",
"features": ["temperature", "humidity"],
"inputSize": 30,
"outputSize": 1
}'
Python (requests)
import os
import requests
# Note the /v1/ at the end
BASE_URL = "https://api.thingbook.io/access/api/driftmind/v1"
headers = {"Auth": os.environ["DRIFTMIND_TOKEN"], "Content-Type": "application/json"}
payload = {
"forecasterName": "Temperature Forecaster",
"features": ["temperature", "humidity"],
"inputSize": 30,
"outputSize": 1
}
r = requests.post(f"{BASE_URL}/forecasters", json=payload, headers=headers)
r.raise_for_status()
forecaster_id = r.json()["forecasterId"]
print("forecasterId:", forecaster_id)
Java (JAX-RS Client)
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
public class CreateForecasterExample {
public static void main(String[] args) {
String baseUrl = "https://api.thingbook.io/access/api/driftmind/v1";
String token = System.getenv("DRIFTMIND_TOKEN");
String payload = """
{
"forecasterName": "Temperature Forecaster",
"features": ["temperature", "humidity"],
"inputSize": 30,
"outputSize": 1
}
""";
Client client = ClientBuilder.newClient();
Response resp = client.target(baseUrl + "/forecasters")
.request(MediaType.APPLICATION_JSON)
.header("Auth", token)
.post(Entity.json(payload));
String body = resp.readEntity(String.class);
System.out.println(resp.getStatus() + " " + body);
}
}
Feed Observations
Feed time-aligned arrays for each feature. All feature arrays must have the same length.
POST /driftmind/v1/forecasters/{id}/observations
curl
curl -X POST https://api.thingbook.io/access/api/driftmind/v1/forecasters/abc123-xyz789/observations \
-H "Auth: $DRIFTMIND_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"temperature": [18.0, 19.5, 20.1, 20.7],
"humidity": [0.62, 0.60, 0.58, 0.59]
}'
Python
import os
import requests
BASE_URL = "https://api.thingbook.io/access/api/driftmind/v1"
headers = {"Auth": os.environ["DRIFTMIND_TOKEN"], "Content-Type": "application/json"}
forecaster_id = "abc123-xyz789"
payload = {
"temperature": [18.0, 19.5, 20.1, 20.7],
"humidity": [0.62, 0.60, 0.58, 0.59]
}
# Note: POST to .../forecasters/{id}/observations
url = f"{BASE_URL}/forecasters/{forecaster_id}/observations"
r = requests.post(url, json=payload, headers=headers)
r.raise_for_status()
print(r.json())
Java (JAX-RS Client)
String forecasterId = "abc123-xyz789";
String payload = """
{
"temperature": [18.0, 19.5, 20.1, 20.7],
"humidity": [0.62, 0.60, 0.58, 0.59]
}
""";
Response resp = client.target(baseUrl + "/forecasters/" + forecasterId + "/observations")
.request(MediaType.APPLICATION_JSON)
.header("Auth", token)
.post(Entity.json(payload));
System.out.println(resp.getStatus() + " " + resp.readEntity(String.class));
Request Predictions
Request a forecast for a forecaster. If insufficient data exists, the API returns
422 FORECAST_NOT_READY.
GET /driftmind/v1/forecasters/{id}/predictions
curl -X GET https://api.thingbook.io/access/api/driftmind/v1/forecasters/abc123-xyz789/predictions \
-H "Auth: $DRIFTMIND_TOKEN"
Not enough data (422)
{
"error": "FORECAST_NOT_READY"
}
Understand the Response
The prediction response includes an overall anomaly score and a per-feature results map.
{
"anomalyScore": 0.27,
"numberOfClusters": 12,
"features": {
"temperature": {
"timestamps": ["2025-12-31 10:00:00"],
"predictions": [20.7],
"upperConfidence": [21.3],
"lowerConfidence": [20.1],
"anomalyScore": 0.12,
"forecastingMethod": "CLUSTER",
"numberOfClusters": 4
},
"humidity": {
"timestamps": ["2025-12-31 10:00:00"],
"predictions": [0.59],
"upperConfidence": [0.61],
"lowerConfidence": [0.57],
"anomalyScore": 0.42,
"forecastingMethod": "CLUSTER",
"numberOfClusters": 8
}
}
}
| Field | Description |
|---|---|
anomalyScore |
Average anomaly score across all features (rounded to 2 decimals). |
numberOfClusters |
Total clusters across all features (sum of per-feature values). |
features |
Map keyed by feature name containing per-feature forecast outputs and metadata. |
predictions |
Forecasted values for the horizon. |
upperConfidence / lowerConfidence |
Confidence bounds per forecast point. |
forecastingMethod |
CLUSTER — normal operation; the model has formed stable clusters and is generating confident forecasts. FALLBACK — the model is still warming up or encountered an unstable state; predictions are based on simpler heuristics and anomaly scores are less reliable. Feed more observations and the method will transition to CLUSTER automatically. |
List all Forecasters
Retrieve a list of all forecasters belonging to your API token, including metadata like creation time and usage statistics.
GET /driftmind/v1/forecasters
curl
curl -X GET https://api.thingbook.io/access/api/driftmind/v1/forecasters \
-H "Auth: $DRIFTMIND_TOKEN"
Python (requests)
# Assumes BASE_URL and headers are defined
r = requests.get(f"{BASE_URL}/forecasters", headers=headers)
r.raise_for_status()
print(r.json())
Java (JAX-RS Client)
Client client = ClientBuilder.newClient();
Response resp = client.target(baseUrl + "/forecasters")
.request(MediaType.APPLICATION_JSON)
.header("Auth", token)
.get();
System.out.println(resp.readEntity(String.class));
Get Forecaster Data
Retrieve the most recent observations currently held in the forecaster's memory buffer. This is useful for validation and debugging to ensure data is being fed correctly.
GET /driftmind/v1/forecasters/{id}/observations
curl
curl -X GET https://api.thingbook.io/access/api/driftmind/v1/forecasters/abc123-xyz789/observations \
-H "Auth: $DRIFTMIND_TOKEN"
Python (requests)
forecaster_id = "abc123-xyz789"
url = f"{BASE_URL}/forecasters/{forecaster_id}/observations"
r = requests.get(url, headers=headers)
r.raise_for_status()
print(r.json())
Java (JAX-RS Client)
String forecasterId = "abc123-xyz789";
Response resp = client.target(baseUrl + "/forecasters/" + forecasterId + "/observations")
.request(MediaType.APPLICATION_JSON)
.header("Auth", token)
.get();
System.out.println(resp.readEntity(String.class));
Get Forecaster Details
Retrieve the specific configuration of a forecaster, including its input/output sizes, feature names, and internal parameters.
GET /driftmind/v1/forecasters/{id}
curl
curl -X GET https://api.thingbook.io/access/api/driftmind/v1/forecasters/abc123-xyz789 \
-H "Auth: $DRIFTMIND_TOKEN"
Python (requests)
forecaster_id = "abc123-xyz789"
url = f"{BASE_URL}/forecasters/{forecaster_id}"
r = requests.get(url, headers=headers)
r.raise_for_status()
details = r.json()
print(f"Name: {details['forecasterName']}")
print(f"Config: {details['configuration']}")
Java (JAX-RS Client)
String forecasterId = "abc123-xyz789";
Response resp = client.target(baseUrl + "/forecasters/" + forecasterId)
.request(MediaType.APPLICATION_JSON)
.header("Auth", token)
.get();
System.out.println(resp.readEntity(String.class));
Error Handling
All errors are returned as:
{
"error": "ERROR_CODE",
"details": ["optional", "context"]
}
| Status | Code | Meaning | Action |
|---|---|---|---|
| 401 | TOKEN_REJECTED |
Token missing or invalid | Check the Auth header |
| 402 | CREDIT_EXHAUSTED |
Insufficient credit | Top up / change plan / reduce calls |
| 404 | FORECASTER_NOT_FOUND |
Forecaster does not exist | Verify forecasterId |
| 422 | FORECAST_NOT_READY |
Not enough data to forecast | Feed more observations and retry |
| 500 | REDIS_UNAVAILABLE |
Temporary backend issue | Retry with backoff |
Delete a Forecaster
Deletes a forecaster and its associated data. This cannot be undone.
DELETE /driftmind/v1/forecasters/{id}
curl -X DELETE https://api.thingbook.io/access/api/driftmind/v1/forecasters/abc123-xyz789 \
-H "Auth: $DRIFTMIND_TOKEN"
Success response
{
"message": "FORECASTER_DELETED"
}