Go SDK
The official Go SDK is published as go.sybilion.dev/sybilion. It ships two packages in one module:
sybilionatgo.sybilion.dev/sybilion— the hand-written wrapper exposed to users (New,Options, direct methods,WaitForecast, pagination callbacks, ...).sybilionapiatgo.sybilion.dev/sybilion/api— the OpenAPI-generated low-level client and models. Exposed viac.DefaultAPI()for endpoints not yet wrapped.
This page documents the wrapper's idioms. For canonical use cases (forecasts, drivers, alerts, account, regions/categories), see the Features section — every example there has a Go tab.
Install
go get go.sybilion.dev/sybilion@latestRequires Go 1.25+.
Construct a client
package main
import (
"context"
"fmt"
"log"
"os"
"go.sybilion.dev/sybilion"
)
func main() {
// Token read from SYBILION_API_TOKEN automatically:
c := sybilion.New(sybilion.Options{})
// Or pass it explicitly:
c = sybilion.New(sybilion.Options{
Token: os.Getenv("SYBILION_API_TOKEN"),
})
me, err := c.Me(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(me.GetUserId(), me.GetAvailableEurCents())
}When Options.Token is empty, New reads SYBILION_API_TOKEN from the environment. If both are empty, the client makes unauthenticated requests (only /health works).
Options fields
| Field | Default | Notes |
|---|---|---|
Token | empty | Bearer token. When empty, SYBILION_API_TOKEN env var is read. |
BaseURL | resolved at runtime | API origin without trailing slash. See resolution rules below. |
HTTPClient | &http.Client{Timeout: 60 * time.Second} | Inject your own for custom transports, retries, or different timeouts. |
UserAgent | generator default | Override to brand outgoing requests. |
Base URL resolution
Options.BaseURL is resolved in this order:
- Explicit
Options.BaseURL. SYBILION_API_BASE_URLenvironment variable (constantsybilion.EnvSybilionAPIBaseURL).- The compiled-in default
sybilion.DefaultPublicAPIBaseURL(currentlyhttps://api.sybilion.dev).
Trailing slashes are stripped.
Wrapper methods
Client exposes a method for every endpoint:
| Method | Endpoint |
|---|---|
Me(ctx) | GET /api/v1/me |
SubmitForecast(ctx, req) | POST /api/v1/forecasts |
GetForecast(ctx, id) | GET /api/v1/forecasts/{id} |
GetForecastArtifact(ctx, id, name) | GET /api/v1/forecasts/{id}/artifacts/{name} |
WaitForecast(ctx, jobID, poll) | polling helper |
GetDrivers(ctx, req) | POST /api/v1/drivers |
GetAlerts(ctx, req) | POST /api/v1/alerts |
ForEachJobsPage(ctx, sort, order, limit, fn) | pagination helper |
ForEachUsagePage(ctx, sort, order, limit, fn) | pagination helper |
ListCategories(ctx) | GET /api/v1/categories |
ListRegions(ctx) | GET /api/v1/regions |
For endpoints not yet wrapped, c.DefaultAPI() returns the *sybilionapi.DefaultAPIService. Method names mirror the OpenAPI operationId: ApiV1MeGet, ApiV1ForecastsPost, ApiV1ForecastsIdGet, ApiV1RegionsGet, etc. The fluent builder returns (*Model, *http.Response, error) from Execute().
regions, _, err := c.DefaultAPI().ApiV1RegionsGet(ctx).Execute()WaitForecast — poll until settled
import "time"
ctx := context.Background()
acc, err := c.SubmitForecast(ctx, *body)
if err != nil { log.Fatal(err) }
job, err := c.WaitForecast(ctx, acc.GetJobId(), 2*time.Second)
if err != nil { log.Fatal(err) }
fmt.Println(job.GetStatus(), job.GetEurCentsFinal())
for _, a := range job.GetArtifacts() {
fmt.Println(a.GetName(), a.GetSize())
}Behaviour:
- Polls
GET /api/v1/forecasts/{id}everypollinterval (no jitter, no backoff). - Returns the response as soon as
settled == true— works forcompleted,failed, andcanceledjobs. - Honors
ctx: cancel the context to stop polling. The wrapper returnsctx.Err().
For a hard wall-clock cap, wrap the call in context.WithTimeout:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
job, err := c.WaitForecast(ctx, acc.GetJobId(), 2*time.Second)c.Forecasts().Wait(ctx, jobID, poll) is an alias for c.WaitForecast kept for backwards compatibility.
GetAlerts — synchronous alert detection
c.GetAlerts calls POST /api/v1/alerts and returns the result immediately — no polling required.
package main
import (
"context"
"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")})
meta := api.NewTimeseriesMetadata("Brent Crude Oil Price Monthly")
meta.SetDescription("Monthly average Brent crude oil spot price in USD/barrel.")
meta.SetKeywords([]string{"oil", "brent", "energy", "commodity"})
filters := api.NewFilters()
filters.SetCategories([]int32{3, 7})
filters.SetRegions([]int32{42})
filters.SetLimit(25)
alerts, err := c.GetAlerts(context.Background(), sybilion.AlertsRequest{
Metadata: *meta,
ContextEnriched: false,
Filters: filters,
DateFrom: "2024-01-01",
})
if err != nil {
log.Fatal(err)
}
for _, a := range alerts {
fmt.Println(a.Name, a.PctChange, a.Trending)
}
}AlertsRequest fields:
| Field | Type | Notes |
|---|---|---|
Metadata | api.TimeseriesMetadata | Required. Title, description, keywords describing the series. |
ContextEnriched | bool | Required. Set to true if the metadata was already enriched upstream; false to let the engine enrich it. |
Filters | *api.Filters | Optional. Scope by category / region ids and cap item count with SetLimit. |
DateFrom | string | Optional. Earliest date bound for alert events (YYYY-MM-DD). |
DateTo | string | Optional. Latest date bound for alert events (YYYY-MM-DD). |
Returns ([]sybilion.AlertItem, error). Each AlertItem has Name, PctChange, Trending, and News []NewsItem. See POST /api/v1/alerts for the full response shape.
Pagination callbacks
ForEachUsagePage and ForEachJobsPage walk paginated endpoints page-by-page. The callback receives each page and returns (continueNext bool, err error) — return false to stop early.
// Walk all usage events.
err := c.ForEachUsagePage(ctx, "created_at", "desc", 50, func(ctx context.Context, page *api.ApiV1UsageGet200Response) (bool, error) {
for _, ev := range page.GetUsageEvents() {
fmt.Println(ev.GetId(), ev.GetEurCentsCharged())
}
return true, nil // continue to the next page
})
if err != nil { log.Fatal(err) }
// Walk completed jobs only.
err = c.ForEachJobsPage(ctx, "created_at", "desc", 50, func(ctx context.Context, page *api.ApiV1JobsGet200Response) (bool, error) {
for _, j := range page.GetJobs() {
fmt.Println(j.GetJobId(), j.GetStatus())
}
return true, nil
})Iteration stops automatically when the last page is reached, or when the callback returns false or a non-nil error.
Error handling
Wrapper methods return a plain error whose message is the error field from the API response body. If the body can't be parsed, the original *api.GenericOpenAPIError is returned as-is.
me, err := c.Me(ctx)
if err != nil {
log.Fatal(err) // prints the API error message
}When you need the HTTP status code — for example to branch on 402 vs 422 — use DefaultAPI() directly, which returns (*Model, *http.Response, error):
resp, httpResp, err := c.DefaultAPI().ApiV1ForecastsPost(ctx).
ForecastRequestV1(*body).
Execute()
if err != nil {
log.Printf("status=%d body=%s", httpResp.StatusCode, ...)
}
_ = respCustom HTTP client
Inject any *http.Client to replace timeouts, transport, retries, or proxies:
import (
"crypto/tls"
"net/http"
"os"
"time"
"go.sybilion.dev/sybilion"
)
httpc := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{MinVersion: tls.VersionTLS12},
MaxIdleConns: 50,
IdleConnTimeout: 90 * time.Second,
},
}
c := sybilion.New(sybilion.Options{
Token: os.Getenv("SYBILION_API_TOKEN"),
HTTPClient: httpc,
UserAgent: "my-app/1.0",
})For per-call cancellation and timeouts, use context.WithTimeout / context.WithCancel instead of mutating the *http.Client.
Versioning
The SDK uses SemVer independently of the API server version; minor releases stay backward-compatible, breaking changes bump the major. Pin to a tag (go get go.sybilion.dev/[email protected]) for production builds.
See also
- Features — full use-case walkthroughs with Go tabs.
- Alerts · Drivers — synchronous endpoints with SDK wrappers.
- Using curl · Python SDK · R SDK · Java SDK.
- Package page:
go.sybilion.dev/sybilionon pkg.go.dev.