API reference
One endpoint. Nine quantiles.
Authenticate with an API key, send observations, receive a median forecast and quantile bands. Two endpoints, one auth header, one error envelope.
Working in n8n? The VecTime node does all of this for you — rows in, forecast rows out, no HTTP node to wire up.
Authentication
Send your key as a bearer token. X-API-Key is accepted as an alternative for clients that reserve the Authorization header.httpAuthorization: Bearer vct_live_xxxxxxxxxxxxxxxxxxxxxxxx# orX-API-Key: vct_live_xxxxxxxxxxxxxxxxxxxxxxxx
Keys are stored as a peppered HMAC — we cannot recover a lost key, only issue a new one. Treat vct_live_* keys as production credentials and keep them server-side.
POST
Forecast one or many series in a single model pass./v1/forecast
| Field | Type | Required | Description |
|---|---|---|---|
| series | number[] | number[][] | Yes | The historical observations, oldest first, evenly spaced. Pass a flat array for one series or an array of arrays to batch. Each series needs at least 2 points; anything longer than your plan's context window is rejected rather than silently truncated. |
| horizon | integer | Yes | How many future steps to predict. Capped by your plan's max horizon. |
| quantiles | boolean | No | Return the nine decile quantiles alongside the median. Defaults to true on plans that include quantiles. |
Examples
Python
pythonimport os, requestsresp = requests.post("https://api.vectime.cloud/v1/forecast",headers={"Authorization": f"Bearer {os.environ['VECTIME_API_KEY']}"},json={# A single series, or a list of series to batch them in one call."series": [[412, 430, 455, 471, 502, 538, 561, 590]],"horizon": 12,"quantiles": True,},timeout=120,)resp.raise_for_status()out = resp.json()median = out["forecasts"][0]["point"]p10 = out["forecasts"][0]["quantiles"]["q10"]p90 = out["forecasts"][0]["quantiles"]["q90"]
TypeScript
typescriptconst res = await fetch("https://api.vectime.cloud/v1/forecast", {method: "POST",headers: {Authorization: `Bearer ${process.env.VECTIME_API_KEY}`,"Content-Type": "application/json",},body: JSON.stringify({series: [[412, 430, 455, 471, 502, 538, 561, 590]],horizon: 12,quantiles: true,}),});if (res.status === 429) {// Rate limited: honour the server's own backoff hint.const wait = Number(res.headers.get("Retry-After") ?? 1);await new Promise((r) => setTimeout(r, wait * 1000));}const { forecasts } = await res.json();
GET
Reports the active model plus the ceilings your plan applies, so a client can discover limits instead of hard-coding them./v1/models
Rate limits and quota
Limits are enforced per API key with a token bucket: you may spike up to your plan's burst size, then settle at the sustained per-minute rate. Every response carries the current state.httpRateLimit-Limit: 60 # requests per minute on this planRateLimit-Remaining: 41 # tokens left in the bucket right nowRateLimit-Reset: 19 # seconds until the bucket is full againX-Quota-Limit: 50000 # monthly call allowanceX-Quota-Used: 12043 # calls consumed this UTC monthRetry-After: 2 # only on 429
Errors
Every failure uses the same envelope.json{"error": {"code": "horizon_limit_exceeded","message": "horizon 500 exceeds your plan's maximum of 128","details": { "max_horizon": 128, "plan": "starter" }}}
| Status | Code | Meaning |
|---|---|---|
| 401 | missing_api_key / invalid_api_key / revoked_api_key | The key is absent, unknown, or revoked. Not retryable. |
| 402 | quota_exceeded | The monthly call quota is spent. Upgrade, or wait for the UTC month to roll over. |
| 403 | account_suspended | The account is suspended. Contact support. |
| 422 | invalid_request | The payload is malformed — a non-finite value, an empty series, horizon < 1. |
| 422 | horizon_limit_exceeded / context_limit_exceeded / series_limit_exceeded | The request is larger than your plan allows. `details` carries the actual ceiling. |
| 429 | rate_limit_exceeded | Too many requests per minute. Retry after the seconds given in Retry-After. |
| 503 | model_unavailable | The model is still warming up. Retryable within a few seconds. |
| 502 | inference_failed | The forecasting backend failed. Retry with backoff; the call is not billed. |