Hubfly spaceDocs
Console

SDK · Go

Go SDK

github.com/hubfly/hubfly-sdk/go is the official Go client for the Hubfly space platform. It is built on the standard library alone, takes a context.Context on every call, and returns typed responses.

Install

go get github.com/hubfly/hubfly-sdk/go

The module requires Go 1.20 or later and pulls in no third-party dependencies, so it adds nothing to your own dependency graph beyond itself.

Creating a client

hubfly.NewClient takes functional options. With no options it reads the token from the HUBFLY_TOKEN environment variable and talks to the production API.

Go
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	hubfly "github.com/hubfly/hubfly-sdk/go"
)

func main() {
	client := hubfly.NewClient(
		hubfly.WithToken("hf_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"),
		hubfly.WithBaseURL("https://api.hubfly.space"),
		hubfly.WithTimeout(15*time.Second),
	)

	ctx := context.Background()

	health, err := client.System.Health(ctx)
	if err != nil {
		log.Fatalf("health check failed: %v", err)
	}

	fmt.Println("API status:", health.Data.Status)
}
OptionDefaultDescription
WithToken(string)$HUBFLY_TOKENPersonal access token, sent as a bearer token on every request.
WithBaseURL(string)https://api.hubfly.spaceOverride the API host, for example to test against a staging environment.
WithTimeout(time.Duration)30sTimeout applied to the underlying http.Client.
WithHTTPClient(*http.Client)http.DefaultClientSupply your own client for custom transports, proxies or instrumentation.

A *hubfly.Client is safe for concurrent use. Build one at start-up and share it, rather than creating a client per request.

Context and timeouts

Every method takes a context.Context as its first argument. Use it to bound a call, or to cancel it when the surrounding request is abandoned. The context deadline wins over WithTimeout when it is shorter.

Go
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()

projects, err := client.Projects.List(ctx)
if errors.Is(err, context.DeadlineExceeded) {
	// the call ran out of time — safe to retry, GET requests are idempotent
}

Response shape

Methods return a typed wrapper around the API envelope, so the resource itself lives under.Data and request metadata under .Meta.

Go
projects, err := client.Projects.List(ctx)
if err != nil {
	return err
}

projects.Data          // []hubfly.Project
projects.Meta.RequestID // "req_8f3a1d9…" — quote this in support requests

Projects and containers

A project is the isolation boundary; containers live inside it. Container calls take the project ID because every container is scoped to one.

Go
// List every project on the account
projects, err := client.Projects.List(ctx)

// Create a project
project, err := client.Projects.Create(ctx, hubfly.CreateProjectParams{
	Name:   "backend-api",
	Region: "us-east-1",
})

// Deploy a container into it
container, err := client.Containers.Create(ctx, hubfly.CreateContainerParams{
	ProjectID: project.Data.ID,
	Name:      "api-server",
	Image:     "golang:1.22-alpine",
	Ports: []hubfly.PortMapping{
		{Container: 8080, Protocol: "tcp"},
	},
})

// Lifecycle operations
_, err = client.Containers.Restart(ctx, project.Data.ID, container.Data.ID)

Deletes are not recoverable

Projects.Delete tears down every container, volume and reservation in the project. There is no undo and no grace period, so guard it behind a confirmation in any tooling you build.

Load balancers

Go
lb, err := client.LoadBalancers.Create(ctx, hubfly.CreateLoadBalancerParams{
	ProjectID: "proj_123",
	Name:      "ingress-lb",
	Algorithm: "round_robin",
})

// Remove the balancer when it is no longer needed.
_, err = client.LoadBalancers.Delete(ctx, "proj_123", lb.Data.ID)

Networking and firewall

Go
// Private network state for the project
netAccess, err := client.Network.Get(ctx, "proj_123")

// Current ingress firewall configuration
firewall, err := client.Network.GetFirewall(ctx, "proj_123")

for _, rule := range firewall.Data.Rules {
	fmt.Printf("%s %s %s -> %s\n",
		rule.Direction, rule.Protocol, rule.CIDR, rule.Action)
}

Firewall writes are API-only in this SDK release

The Go package currently exposes GetFirewall for inspection. Use the API endpoint explorer for firewall update requests until a typed write method is added.

Port reservations

Reserve a public port on the edge, then map it to a container port. The two steps are separate so a reservation survives the container behind it being replaced.

Go
reservation, err := client.Ports.Reserve(ctx, "proj_123", hubfly.ReservePortParams{
	Protocol: "tcp",
	Port:     6379,
})

// Release it again when the service is gone
_, err = client.Ports.Remove(ctx, "proj_123", reservation.Data.ReservationID)

Volumes

A volume is persistent block storage that outlives the container mounted on it.

Go
vol, err := client.Volumes.Create(ctx, hubfly.CreateVolumeParams{
	ProjectID: "proj_123",
	Name:      "redis-data",
	SizeGB:    10,
})

Hibernation

Hibernating a project stops its containers and releases their memory while keeping volumes and configuration intact. Restoring brings everything back in the same shape.

Go
status, err := client.Hibernation.Hibernate(ctx, "proj_123")
fmt.Println("hibernated:", status.Data.Hibernated)

restored, err := client.Hibernation.Restore(ctx, "proj_123")

Developer sub-accounts

Use client.Subaccounts and client.PlatformKeys for tenant control. A client configured with hubfly.WithSubaccount addsX-HubFly-Subaccount to ordinary resource calls made with a platform key.

Go
platform := hubfly.NewClient(
	hubfly.WithToken(os.Getenv("HUBFLY_PLATFORM_TOKEN")),
)

created, err := platform.Subaccounts.Create(ctx, hubfly.CreateSubaccountParams{
	Name:        "Customer 1042",
	ExternalRef: "customer_1042",
})

tenant := hubfly.NewClient(
	hubfly.WithToken(os.Getenv("HUBFLY_PLATFORM_TOKEN")),
	hubfly.WithSubaccount(created.Data.ID),
)

projects, err := tenant.Projects.List(ctx)

See Sub-account API for wallet units, idempotency, isolation rules, and lifecycle errors.

Handling errors

API errors come back as a *hubfly.APIError. Unwrap it witherrors.As so the check still works if the error has been wrapped further up the call stack.

Go
_, err := client.Projects.Get(ctx, "proj_does_not_exist")

var apiErr *hubfly.APIError
if errors.As(err, &apiErr) {
	fmt.Println("status:", apiErr.StatusCode)  // 404
	fmt.Println("message:", apiErr.Message)    // "Project not found"
	fmt.Println("payload:", apiErr.RawPayload) // raw JSON body; may include server details
}

Errors and retries covers what each status code means and which failures are worth retrying.

Standard library only

The client is built on net/http, context andencoding/json. There is nothing to reconcile with the HTTP stack your service already uses, whichever framework it is built on.
Something unclear or out of date? Emailsupport@hubfly.spaceBack to top