Quickstart
This page helps you build a complete forecast job using the Sybilion API. All you need is a Sybilion account to get started. You can use Sybilion in three ways — direct API calls (curl or any HTTP client), our Python, Go, R, and Java SDKs, or via MCP to connect AI assistants like Claude or ChatGPT.
1. Sign up or sign in
Create a new account or sign in at the Developers Portal:
2. Create an API key
In the Developers Portal, navigate to API keys and create a new key.
Important: The full secret is shown only once, at creation time. Copy it immediately — it starts with
sk_ops_…and cannot be retrieved again.
The examples in this guide all read from $SYBILION_API_TOKEN. Set it in your shell/terminal using this command:
export SYBILION_API_TOKEN="sk_ops_..."3. Pick a client
The base URL is https://api.sybilion.dev. Choose the client that fits your stack:
# Already on most systems. To install if needed:
# macOS: brew install curl
# Debian/Ubuntu: sudo apt install -y curl
# Windows: winget install curl.curlpip install sybiliongo get go.sybilion.dev/sybilion@latestinstall.packages("sybilion")<!-- Maven (pom.xml) -->
<dependency>
<groupId>dev.sybilion</groupId>
<artifactId>sybilion</artifactId>
</dependency>SDK packages: Python — sybilion on PyPI · Go — go.sybilion.dev/sybilion on pkg.go.dev · R — sybilion on CRAN · Java — dev.sybilion:sybilion on Maven Central.
4. Verify authentication — GET /api/v1/me
Call GET /api/v1/me to confirm your key works and see your current balance and tier.
curl -sS \
-H "Authorization: Bearer $SYBILION_API_TOKEN" \
https://api.sybilion.dev/api/v1/meimport os
from sybilion import Client
c = Client(token=os.environ["SYBILION_API_TOKEN"])
me = c.me()
print(me.user_id, me.available_eur_cents, me.api_usage_tier)package main
import (
"context"
"fmt"
"os"
"go.sybilion.dev/sybilion"
)
func main() {
c := sybilion.New(sybilion.Options{Token: os.Getenv("SYBILION_API_TOKEN")})
me, _, err := c.DefaultAPI().ApiV1MeGet(context.Background()).Execute()
if err != nil { panic(err) }
fmt.Println(me.GetUserId(), me.GetAvailableEurCents(), me.GetApiUsageTier())
}library(sybilion)
cl <- sybilion_client(token = Sys.getenv("SYBILION_API_TOKEN"))
me <- cl$raw$ApiV1MeGet()$content
cat(me$user_id, me$available_eur_cents, me$api_usage_tier, "\n")import com.sybilion.Client;
import com.sybilion.Options;
Client c = new Client(Options.builder().token(System.getenv("SYBILION_API_TOKEN")).build());
var me = c.defaultApi().apiV1MeGet();
System.out.println(me.getUserId() + " " + me.getAvailableEurCents() + " " + me.getApiUsageTier());A successful response looks like this:
{
"user_id": "1f2a8b3e-4c5d-46d7-9a01-2b3c4d5e6f70",
"balance_eur_cents": 1234,
"available_eur_cents": 1134,
"api_usage_tier": 1
}available_eur_centsis your spendable balance (balance minus any active holds). Monetary values are always integer EUR cents (100=€1.00).api_usage_tieris your current pricing tier.- A
401means your token is missing or invalid — double-check the value you exported.
See GET /api/v1/me for the full field references.
5. Submit a forecast — POST /api/v1/forecasts
Save the body below as forecast_body.json. This example uses the shortest possible horizon (soft_horizon: 1), which needs a minimum of 40 monthly observations. Your most recent data point cannot be older than 12 months. Replace the timeseries values with your own data.
Date format: Each key must be the first day of the month in
YYYY-MM-DDformat (e.g.2024-06-01, not2024-06-15). Any other day-of-month will be rejected.
{
"pipeline_version": "v1",
"frequency": "monthly",
"soft_horizon": 1,
"recency_factor": 0.5,
"timeseries_metadata": {
"title": "Monthly Widget Sales Europe",
"description": "Monthly unit sales of widgets in the European market.",
"keywords": ["widget", "sales", "europe", "consumer goods", "retail"]
},
"timeseries": {
"2021-12-01": 218.5,
"2022-01-01": 148.1,
"2022-02-01": 145.9,
"2022-03-01": 162.4,
"2022-04-01": 168.7,
"2022-05-01": 166.2,
"2022-06-01": 178.5,
"2022-07-01": 172.3,
"2022-08-01": 168.9,
"2022-09-01": 181.4,
"2022-10-01": 189.7,
"2022-11-01": 204.8,
"2022-12-01": 218.5,
"2023-01-01": 155.3,
"2023-02-01": 152.7,
"2023-03-01": 170.1,
"2023-04-01": 176.4,
"2023-05-01": 174.0,
"2023-06-01": 186.2,
"2023-07-01": 180.5,
"2023-08-01": 177.1,
"2023-09-01": 190.3,
"2023-10-01": 198.4,
"2023-11-01": 213.9,
"2023-12-01": 227.6,
"2024-01-01": 162.8,
"2024-02-01": 160.2,
"2024-03-01": 178.5,
"2024-04-01": 184.9,
"2024-05-01": 182.3,
"2024-06-01": 194.7,
"2024-07-01": 188.4,
"2024-08-01": 185.0,
"2024-09-01": 198.6,
"2024-10-01": 207.3,
"2024-11-01": 223.1,
"2024-12-01": 237.8,
"2025-01-01": 170.4,
"2025-02-01": 168.1,
"2025-03-01": 186.7
}
}Then submit it:
curl -sS -X POST https://api.sybilion.dev/api/v1/forecasts \
-H "Authorization: Bearer $SYBILION_API_TOKEN" \
-H "Content-Type: application/json" \
-d @forecast_body.jsonimport json
import os
from sybilion import Client
c = Client(token=os.environ["SYBILION_API_TOKEN"])
with open("forecast_body.json", encoding="utf-8") as f:
body = json.load(f)
resp = c.submit_forecast(body)
print(resp.job_id, resp.poll_url)package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"go.sybilion.dev/sybilion"
api "go.sybilion.dev/sybilion/api"
)
func main() {
c := sybilion.New(sybilion.Options{Token: os.Getenv("SYBILION_API_TOKEN")})
data, err := os.ReadFile("forecast_body.json")
if err != nil { log.Fatal(err) }
var body api.ForecastRequestV1
if err := json.Unmarshal(data, &body); err != nil { log.Fatal(err) }
resp, err := c.SubmitForecast(context.Background(), body)
if err != nil { log.Fatal(err) }
fmt.Println(resp.GetJobId(), resp.GetPollUrl())
}library(jsonlite)
library(sybilion)
cl <- sybilion_client(token = Sys.getenv("SYBILION_API_TOKEN"))
payload <- jsonlite::fromJSON("forecast_body.json")
req <- ForecastRequestV1$new(
frequency = payload$frequency,
pipeline_version = payload$pipeline_version,
recency_factor = payload$recency_factor,
timeseries = payload$timeseries,
timeseries_metadata = TimeseriesMetadata$new(
title = payload$timeseries_metadata$title,
description = payload$timeseries_metadata$description,
keywords = payload$timeseries_metadata$keywords
),
backtest = payload$backtest,
soft_horizon = payload$soft_horizon
)
started <- cl$raw$ApiV1ForecastsPost(req)
cat(started$job_id, started$poll_url, "\n")import com.fasterxml.jackson.databind.ObjectMapper;
import com.sybilion.Client;
import com.sybilion.Options;
import com.sybilion.generated.model.ForecastRequestV1;
import java.nio.file.Files;
import java.nio.file.Path;
Client c = new Client(Options.builder().token(System.getenv("SYBILION_API_TOKEN")).build());
ObjectMapper om = new ObjectMapper().findAndRegisterModules();
ForecastRequestV1 req = om.readValue(
Files.readString(Path.of("forecast_body.json")), ForecastRequestV1.class);
var resp = c.defaultApi().apiV1ForecastsPost(req);
System.out.println(resp.getJobId() + " " + resp.getPollUrl());A successful response is 202 Accepted:
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"poll_url": "/api/v1/forecasts/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}Copy the job_id — you'll need it in the next step. See POST /api/v1/forecasts for the full field reference and validation rules.
6. Poll until completed
Forecasts run asynchronously and typically take a few minutes. Keep checking the job status until settled is true.
JOB_ID="<paste-job-id>"
API="https://api.sybilion.dev"
until curl -sS -H "Authorization: Bearer $SYBILION_API_TOKEN" \
"$API/api/v1/forecasts/$JOB_ID" | grep -qE '"settled"[[:space:]]*:[[:space:]]*true'; do
sleep 2
done
curl -sS -H "Authorization: Bearer $SYBILION_API_TOKEN" \
"$API/api/v1/forecasts/$JOB_ID"import os
from sybilion import Client
c = Client(token=os.environ["SYBILION_API_TOKEN"])
job = c.wait_forecast("<paste-job-id>", poll_s=2.0, timeout_s=3600.0)
print(job.status, job.artifacts)package main
import (
"context"
"fmt"
"log"
"os"
"time"
"go.sybilion.dev/sybilion"
)
func main() {
c := sybilion.New(sybilion.Options{Token: os.Getenv("SYBILION_API_TOKEN")})
jobID := "<paste-job-id>"
job, err := c.WaitForecast(context.Background(), jobID, 2*time.Second)
if err != nil { log.Fatal(err) }
fmt.Println(job.GetStatus(), job.GetEurCentsFinal())
for _, a := range job.GetArtifacts() {
fmt.Println(" -", a.GetName())
}
}library(sybilion)
cl <- sybilion_client(token = Sys.getenv("SYBILION_API_TOKEN"))
job <- cl$wait_forecast("<paste-job-id>", poll_s = 2.0, timeout_s = 3600.0)
cat(job$status, "\n")
for (a in job$artifacts) cat(" -", a$name, "\n")import com.sybilion.Client;
import com.sybilion.Options;
import java.time.Duration;
Client c = new Client(Options.builder().token(System.getenv("SYBILION_API_TOKEN")).build());
var job = c.forecasts().waitUntilSettled(
"<paste-job-id>", Duration.ofSeconds(2), Duration.ofHours(1));
System.out.println(job.getStatus() + " " + job.getEurCentsFinal());
for (var a : job.getArtifacts()) System.out.println(" - " + a.getName());Once status is completed, the response includes how much the forecast cost and an artifacts array listing the files ready to download:
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "completed",
"settled": true,
"eur_cents_final": 3,
"artifacts": [
{ "name": "forecast.json", "href": "/api/v1/forecasts/a1b2c3d4-.../artifacts/forecast.json" },
{ "name": "external_signals.json", "href": "/api/v1/forecasts/a1b2c3d4-.../artifacts/external_signals.json" }
]
}See GET /api/v1/forecasts/:id for the full response shape.
7. Fetch artifacts
Download the forecast results using the artifact names from the artifacts array above.
curl -sS \
-H "Authorization: Bearer $SYBILION_API_TOKEN" \
"https://api.sybilion.dev/api/v1/forecasts/$JOB_ID/artifacts/forecast.json"import json
import os
from sybilion import Client
c = Client(token=os.environ["SYBILION_API_TOKEN"])
data = c.get_forecast_artifact("<paste-job-id>", "forecast.json")
forecast = json.loads(data)
print(forecast["data"]["forecast_series"])package main
import (
"context"
"fmt"
"io"
"log"
"os"
"go.sybilion.dev/sybilion"
)
func main() {
c := sybilion.New(sybilion.Options{Token: os.Getenv("SYBILION_API_TOKEN")})
f, err := c.GetForecastArtifact(context.Background(), "<paste-job-id>", "forecast.json")
if err != nil { log.Fatal(err) }
defer f.Close()
body, _ := io.ReadAll(f)
fmt.Println(string(body))
}library(jsonlite)
library(sybilion)
cl <- sybilion_client(token = Sys.getenv("SYBILION_API_TOKEN"))
cl$raw$ApiV1ForecastsIdArtifactsNameGet(
"<paste-job-id>", "forecast.json", data_file = "forecast.json")
forecast <- jsonlite::fromJSON("forecast.json")
print(forecast$data$forecast_series)import com.fasterxml.jackson.databind.ObjectMapper;
import com.sybilion.Client;
import com.sybilion.Options;
import java.nio.file.Path;
Client c = new Client(Options.builder().token(System.getenv("SYBILION_API_TOKEN")).build());
c.forecasts().downloadArtifactToFile(
"<paste-job-id>", "forecast.json", Path.of("forecast.json"));
var tree = new ObjectMapper().readTree(Path.of("forecast.json").toFile());
System.out.println(tree.get("data").get("forecast_series"));The forecast.json artifact looks like this (our example used soft_horizon: 1, so there is one forecast point):
{
"version": "1.1",
"data": {
"forecast_horizon": 1,
"forecast_start": "2025-04-01",
"forecast_end": "2025-04-01",
"forecast_series": {
"2025-04-01": {
"forecast": 191.3
}
}
}
}The external_signals.json artifact is always present alongside forecast.json and contains the ranked external drivers (macroeconomic indicators, regional and category signals) that influenced the forecast. See Artifact download for the full schema of all artifact files.
Next steps
Explore more features
- Drivers — find the external signals that impact your series, without running a full forecast.
- Alerts — get info about macroeconomic events relevant to your data.
- Regions & categories — browse the dimension catalog to narrow your results.
- Account & usage — check your balance, tier, and charge history.
Go deeper on forecasts
- POST /api/v1/forecasts — full validation rules, along with details on all fields.
- Artifact download — complete schema for
forecast.json,external_signals.json, and backtest files. - Errors & limits — understand
402,422,429, and what each means for your integration.
Connect and integrate
- MCP integrations — use the Sybilion API through Claude, ChatGPT, or TradingView Remix without writing code.
- Python SDK · Go SDK · R SDK · Java SDK · Using curl — language-specific patterns and helpers.
- Tiers — understand how pricing tiers work and when they change.
Get help
- Community & support — Slack, Discord, or email. We're happy to help.