Developers
Timestral API reference
One endpoint turns a CSV into a probabilistic forecast. This page is the contract: authentication, request shape, response shape, errors, credits and rate limits. The OpenAPI file and a sample input/output are linked below.
Base URL
https://timestral.org
Authentication
Send an API key as a bearer token: Authorization: Bearer sk_.... Create a key at Settings → API keys after signing in with an email code.
Quickstart
The endpoint is synchronous. Send the CSV as a string, choose a horizon, and read the median plus the 80% band from data.rows. The full 21-quantile CSV is at data.fileUrl.
curl -sS https://timestral.org/api/forecast \
-H "Authorization: Bearer $TIMESTRAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"csv": "date,sales\n2026-01-01,120\n2026-01-02,135\n2026-01-03,128\n2026-01-04,141\n2026-01-05,150\n2026-01-06,162\n2026-01-07,155\n2026-01-08,168\n",
"steps": 6
}'import os
import requests
csv_text = open("timestral-sample.csv", "r", encoding="utf-8").read()
response = requests.post(
"https://timestral.org/api/forecast",
headers={
"Authorization": f"Bearer {os.environ['TIMESTRAL_API_KEY']}",
"Content-Type": "application/json",
},
json={"csv": csv_text, "steps": 12},
timeout=120,
)
response.raise_for_status()
payload = response.json()
if payload["code"] != 0:
raise RuntimeError(payload["message"])
result = payload["data"]
print(result["taskId"], result["took"])
for row in result["rows"][:5]:
print(row["time"], row["median"], row["low"], row["high"])
print("quantile CSV:", result.get("fileUrl"))const apiKey = process.env.TIMESTRAL_API_KEY;
const response = await fetch("https://timestral.org/api/forecast", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
csv: await Bun.file("timestral-sample.csv").text(),
steps: 12,
}),
});
const payload = await response.json();
if (payload.code !== 0) throw new Error(payload.message);
const { taskId, rows, took, fileUrl } = payload.data;
console.log(taskId, took, rows.length, fileUrl);POST /api/forecast
Forecast one or more numeric series. The first column may be a date or timestamp; if the first row is numeric, the file is read as values only. At least 8 rows, at most 8 numeric columns, and a maximum body size of 2 MB.
| Field | Type | Required | Notes |
|---|---|---|---|
| csv | string | yes | The series as CSV text, up to 2 MB. |
| steps | integer | no | Horizon, 1–1,024. Defaults to 12. |
Response envelope:
{
"code": 0,
"message": "ok",
"data": {
"taskId": "f0c2…",
"columns": ["sales"],
"rows": [
{
"time": "2026-01-09",
"column": "sales",
"low": 151.2,
"median": 164.8,
"high": 178.1
}
],
"took": "3.42 s",
"fileUrl": "https://timestral.org/api/media/uploads/forecast-….csv"
}
}rows contains the median and the 80% band per time step. The full quantile table is in the downloadable CSV. A failed call returns a non-zero code and no data.
Errors and credits
| Code | Meaning | Credit |
|---|---|---|
| Unauthorized | Missing or invalid API key | not charged |
| invalid_csv | Empty, too large or unparseable CSV | not charged |
| too_few_rows | Fewer than 8 rows | not charged |
| no_numeric_column | No numeric series found | not charged |
| too_many_columns | More than 8 numeric columns | not charged |
| invalid_steps | Horizon outside 1–1,024 | not charged |
| insufficient_credits | No credits left | not charged |
| quota_exceeded | Model host is over quota | refunded |
| forecast_failed | Model call failed | refunded |
One credit is charged before the model call and refunded automatically if the call fails. A successful call costs one credit. There is no free API tier. Buy credits on the pricing page.
Rate limits and data handling
- —At least 1.5 seconds between forecast requests per client. The API returns a 429-style error envelope when the limit is hit.
- —The CSV is sent to the Timestral model host for inference. Result files are stored in Cloudflare R2 so the download link outlives the model host session.
- —Uploads are not used to train a model. Do not send personal or regulated data you are not allowed to send to a third-party inference host.
- —Each call creates a task row. Use
taskIdin support requests.
Other endpoints
| Endpoint | Auth | Purpose |
|---|---|---|
| GET /api/health | public | Liveness and build SHA. |
| POST /api/forecast/email | public, rate-limited | Email a browser-generated forecast CSV. Not a general email API. |
| GET /api/apikeys | session cookie | List keys for the signed-in account. |
| POST /api/apikeys | session cookie | Create a key. Body: { title }. |
| DELETE /api/apikeys?id= | session cookie | Soft-delete a key. |
What to read next
CSV format contract
The exact input the model accepts, including missing values and separators.
Evaluate a forecast
MASE, RMSE and 80% coverage: how to backtest before you put a number in a plan.
Forecasting software comparison
When a CSV tool is enough and when you need a platform or a library.
Pricing
Credits, subscriptions and the annual Studio tier.
Last updated: 2026-10-18. The OpenAPI file is served at /openapi.json.