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,Forecasts().Wait,ForEachUsagePage,AsGenericOpenAPIError, ...).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, 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() {
c := sybilion.New(sybilion.Options{
Token: os.Getenv("SYBILION_API_TOKEN"),
})
me, _, err := c.DefaultAPI().ApiV1MeGet(context.Background()).Execute()
if err != nil {
log.Fatal(err)
}
fmt.Println(me.GetUserId(), me.GetAvailableEurCents())
}sybilion.New is constructed from an Options struct. The wrapper does not read the token from the environment — pass it explicitly via Options.Token. The token can be an API key (sk_ops_...) or a dashboard session token; see Authentication.
Options fields
| Field | Default | Notes |
|---|---|---|
Token | empty | Bearer token. When empty the client makes unauthenticated requests (only /health works). |
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).OPERATIONAL_API_BASE_URL(deprecated alias kept for one transition release; constantsybilion.EnvOperationalAPIBaseURL).- The compiled-in default
sybilion.DefaultPublicAPIBaseURL(currentlyhttps://api.sybilion.dev).
Trailing slashes are stripped.
DefaultAPI() — escape hatch to the generated client
c.DefaultAPI() returns the *sybilionapi.DefaultAPIService for any endpoint not yet wrapped. Method names mirror the OpenAPI operationId: ApiV1MeGet, ApiV1ForecastsPost, ApiV1ForecastsIdGet, ApiV1RegionsGet, etc. The fluent builder returns (*Model, *http.Response, error) from Execute().
me, _, err := c.DefaultAPI().ApiV1MeGet(ctx).Execute()
tiers, _, err := c.DefaultAPI().ApiV1TiersGet(ctx).Execute()
regions, _, err := c.DefaultAPI().ApiV1RegionsGet(ctx).Execute()If you need the raw configuration (custom defaults, header injection beyond UserAgent), c.Raw() returns the *sybilionapi.APIClient.
Forecasts().Wait — poll until settled
import "time"
ctx := context.Background()
acc, _, err := c.DefaultAPI().
ApiV1ForecastsPost(ctx).
ForecastRequestV1(*body).
Execute()
if err != nil { log.Fatal(err) }
job, err := c.Forecasts().Wait(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.Forecasts().Wait(ctx, acc.GetJobId(), 2*time.Second)If you need backoff, jitter, or a max-attempts cap, write your own loop calling c.DefaultAPI().ApiV1ForecastsIdGet(ctx, id).Execute().
Error handling
The generated client returns *sybilionapi.GenericOpenAPIError for non-2xx responses with a decodable body. The wrapper exposes sybilion.AsGenericOpenAPIError(err) for ergonomic unwrapping (uses errors.As under the hood, so chained errors work):
import "go.sybilion.dev/sybilion"
acc, resp, err := c.DefaultAPI().
ApiV1ForecastsPost(ctx).
ForecastRequestV1(*body).
Execute()
if err != nil {
if ge, ok := sybilion.AsGenericOpenAPIError(err); ok {
log.Printf("api error status=%d body=%s", resp.StatusCode, ge.Body())
return
}
log.Fatal(err) // network / decode errors land here
}
_ = accThe *http.Response returned alongside err carries the HTTP status code and headers — it's the most reliable way to branch on 402 / 422 / 429 etc., since the SDK doesn't expose typed exceptions per status code.
For a transport / decode-only fallback (when the body can't be parsed at all), the wrapper also defines sybilion.APIError{StatusCode, Body, Message} — used internally for early reads where the generator's helper isn't available. You won't see it on standard endpoints.
Custom 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.
- Using curl and Python SDK.
- Package page:
go.sybilion.dev/sybilionon pkg.go.dev.