Go SDK quickstart
The github.com/driftstackdev/driftstack-api/packages/sdk-go module wraps
the same REST surface as the curl
quickstart. Idiomatic Go: every call takes a
context.Context, returns a typed struct + error,
and the streaming surface is a channel.
1. Install
go get github.com/driftstackdev/driftstack-api/packages/sdk-go@latest
Go ≥ 1.22 is supported. The module has zero non-stdlib runtime
dependencies (it speaks raw JSON over net/http); no
transitive bloat.
2. Construct the client
package main
import (
"context"
"os"
"github.com/driftstackdev/driftstack-api/packages/sdk-go"
)
func main() {
client, err := driftstack.NewClient(driftstack.Config{
APIKey: os.Getenv("DRIFTSTACK_API_KEY"),
// BaseURL defaults to https://api.driftstack.dev; override
// for staging or self-hosted deployments.
})
if err != nil {
panic(err)
}
_ = client
}
The constructor does not make any network calls. Reuse one
client across your process — it is internally pooled via
http.Client with sensible defaults (no
reconfiguration needed for production traffic).
3. Start a session
session, err := client.Sessions.Create(ctx, &driftstack.CreateSessionRequest{
Archetype: "default",
Purpose: driftstack.PurposeProductionCustomer,
})
if err != nil {
return err
}
log.Println(session.ID, session.Status, session.Archetype) session is a strongly typed struct. The status
string is the SessionStatus type with the constants
SessionCreating, SessionReady,
SessionBusy, SessionDestroyed, and
SessionErrored — switch on those for exhaustive
compile-time coverage. The create call doesn't take a target
URL; drive the session to a URL with
client.Sessions.Navigate(...).
4. Drive and finish the session
There is no built-in wait-until-terminal helper. Drive
the session through its lifecycle with
Navigate, Interact,
Wait, Capture, then
Destroy when you're done. Wait blocks
on a server-side condition (selector, URL, time):
_, err = client.Sessions.Navigate(ctx, session.ID, &driftstack.NavigateRequest{
URL: "https://example.com",
})
if err != nil { return err }
_, err = client.Sessions.Wait(ctx, session.ID, &driftstack.WaitRequest{
Condition: driftstack.NewTimeCondition(1000),
})
if err != nil { return err }
shot, err := client.Sessions.Capture(ctx, session.ID, &driftstack.CaptureRequest{
Kind: "screenshot",
})
if err != nil { return err }
log.Println("captured", shot.ByteSize, "bytes")
// Idempotent.
if err := client.Sessions.Destroy(ctx, session.ID); err != nil {
return err
}
Every method takes a context.Context — parent
cancellations / deadlines propagate cleanly through the HTTP
layer. For batch workloads, prefer
webhooks over polling.
5. Paginate over historical sessions
page, err := client.Sessions.List(ctx, &driftstack.ListSessionsQuery{Limit: 50})
if err != nil { return err }
for _, s := range page.Data {
if s.Status == driftstack.SessionDestroyed {
log.Println(s.ID)
}
}
// page.NextCursor is "" when there are no more pages; refeed it as
// query.Cursor on subsequent calls to walk the full history. Error handling
Every SDK method returns a typed error wrapper on non-2xx
responses — one per problem class
(ValidationError, RateLimitError,
ConcurrencyLimitError,
NotFoundError, etc.). Use errors.As
to recover the typed shape (lifted extension fields,
RetryAfterSeconds, etc.); use
errors.Is against the sentinel
(ErrRateLimit, ErrValidation, …) when
you just need category matching:
var rl *driftstack.RateLimitError
if errors.As(err, &rl) {
time.Sleep(time.Duration(rl.RetryAfterSeconds) * time.Second)
// retry
}
var ve *driftstack.ValidationError
if errors.As(err, &ve) {
// ve.Problem carries the per-field issues
}
if errors.Is(err, driftstack.ErrConflict) {
// any 409, regardless of subclass
}
Every typed error embeds an apiError shape with
Status, ProblemType (the RFC 7807
URI), Message, and Problem (the full
parsed problem map). Read additional extension fields off
err.Problem.
Context propagation
Every method takes a context.Context as its first
argument. Cancellation cascades through the underlying HTTP
requests, so a parent deadline (or an HTTP request cancellation
in a Gin / chi / standard http.Server handler)
cleanly aborts in-flight SDK calls. No goroutine leaks even
under heavy concurrent load.
Where to go next
- Full API reference — every endpoint, every field.
- Crypto orders — customer-facing crypto-checkout surface.
- TypeScript SDK — same surface, TS-native.
- Python SDK — same surface, sync + asyncio.
- Webhooks — avoid polling in production.
- Cost monitoring — set alerts before the bill surprises you.
- Error codes — the stable RFC 7807 type URIs the SDK's typed errors carry.
Need help?
[email protected]. We respond within one business day.