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.
FORECAST_NOT_READY if
insufficient data has been fed.
In that case, feed additional observations and retry.
Create a Forecaster
Creates a multivariate forecaster and returns a forecasterId.
POST /driftmind/v1/forecasters
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())
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 |
Method used (e.g., CLUSTER, FALLBACK). |
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 |
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));
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));
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"
}