Skip to content

About

Official Go client (SDK) for the Flashduty Open API — thin, typed, full endpoint coverage

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

229 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-flashduty

English | 中文

Go Reference CI Release License

go-flashduty is the official Go SDK for the Flashduty Open API. Flashduty is an incident management and on-call platform; this client gives Go programs typed access to every public endpoint: incidents, alerts, channels, on-call schedules, status pages, monitors, RUM, and the AI SRE.

Website · API reference · Go package docs · Console · Flashduty CLI

Status: Typed API operations are generated from the Flashduty OpenAPI specification, covered by unit tests, and validated end-to-end against the live API.

Install

go get github.com/flashcatcloud/go-flashduty

Requires Go 1.24+.

Quick start

package main

import (
	"context"
	"fmt"
	"log"

	flashduty "github.com/flashcatcloud/go-flashduty"
)

func main() {
	client, err := flashduty.NewClient("YOUR_APP_KEY")
	if err != nil {
		log.Fatal(err)
	}

	list, resp, err := client.Incidents.List(context.Background(), &flashduty.ListIncidentsRequest{
		Progress:    "Triggered",
		ListOptions: flashduty.ListOptions{Limit: 20},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("request_id=%s total=%d has_next=%t\n", resp.RequestID, resp.Total, resp.HasNextPage)
	for _, inc := range list.Items {
		fmt.Printf("[%s] %s\n", inc.IncidentSeverity, inc.Title)
	}
}

Authentication

Create an APP key in the console (My → APP Key); the API reference describes the steps. NewClient sends it as the app_key query parameter.

To call the API with an OAuth access token instead, use NewClientWithAccessToken; it sends Authorization: Bearer <token> and accepts the same options:

client, err := flashduty.NewClientWithAccessToken(accessToken)

Public and dedicated integrations

Use client.Integrations for public integrations managed in the integration center. They can be connected to channels through subscriptions or routing and require integration permissions. Use client.DedicatedIntegrations for integrations owned by one channel; reads accept Channels Read, Channels Manage, or Integrations Read and require visibility of the owning channel; writes require Channels Manage and management access to that channel. The shared type catalog accepts these three read permissions; scoped App Keys must allow integration.api:read:typeList to query it.

req := &flashduty.ChannelIntegrationListRequest{ChannelID: 20001}
integrations, _, err := client.DedicatedIntegrations.ReadList(ctx, req)

Choose the API from the integration's ownership. An integration ID alone does not identify its scope. The SDK does not switch API groups on a permission error. Both groups authenticate with the management App Key; the returned integration_key authenticates inbound events. List/info include that key and masked settings, so avoid logging complete responses.

Dedicated updates preserve omitted fields. Set Description to a pointer to "" to clear it; nil keeps it. A nil Settings map preserves configuration; a non-nil empty map submits {} as a replacement, subject to the type's validation and secret-preservation rules.

Design

  • Thin and typed. Every method maps to exactly one HTTP call and returns (*T, *Response, error). No hidden cross-endpoint enrichment.
  • Service-grouped. Endpoints are organized into services on the client (client.Incidents, client.Alerts, …), generated from the OpenAPI specification.
  • Composable transport. Cross-cutting concerns (retry, caching, tracing, rate-limit handling) compose as http.RoundTripper middleware via WithTransport.
  • Human-readable timestamps. Response time fields are typed Timestamp (Unix seconds) or TimestampMilli (milliseconds) instead of bare integers, so JSON, logs, and LLM-facing output read as RFC3339 — while the raw epoch is one call away. Request fields stay plain int64.

Options

client, err := flashduty.NewClient("YOUR_APP_KEY",
	flashduty.WithBaseURL("https://api.flashcat.cloud"),
	flashduty.WithTimeout(10*time.Second),
	flashduty.WithUserAgent("my-app/1.0"),
	flashduty.WithHTTPClient(customHTTPClient),
	flashduty.WithTransport(customRoundTripper),
	flashduty.WithLogger(myLogger),
	flashduty.WithRequestHeaders(staticHeaders),
	flashduty.WithRequestHook(func(req *http.Request) { /* e.g. inject traceparent */ }),
)

Pagination

List requests embed ListOptions. Zero values are omitted, so the server defaults apply (page 1, 20 items). Response.Total and Response.HasNextPage describe the result set:

req := &flashduty.ListIncidentsRequest{ListOptions: flashduty.ListOptions{Page: 1, Limit: 100}}
for {
	list, resp, err := client.Incidents.List(ctx, req)
	if err != nil {
		return err
	}
	handle(list.Items)
	if !resp.HasNextPage {
		break
	}
	req.Page++
}

Endpoints that support deep pagination return an opaque cursor in Response.SearchAfterCtx; pass it back in ListOptions.SearchAfterCtx to fetch the next page.

Errors and rate limits

_, _, err := client.Incidents.Info(ctx, &flashduty.IncidentInfoRequest{IncidentID: "does-not-exist"})

var apiErr *flashduty.ErrorResponse
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.Code, apiErr.RequestID)
}

var rl *flashduty.RateLimitError
if errors.As(err, &rl) {
	time.Sleep(rl.RetryAfter)
}

Typed predicates save you the string comparison and see through wrapped errors (errors.As under the hood):

if flashduty.IsNotFound(err) { /* ... */ }
if flashduty.IsRateLimited(err) { /* ... */ }
switch flashduty.ErrorCodeOf(err) {
case flashduty.ErrorCodeAccessDenied, flashduty.ErrorCodeUnauthorized:
	// handle auth failures
}

Timestamps

Time fields on responses are Timestamp (Unix seconds) or TimestampMilli (milliseconds). They marshal to an RFC3339 string in the local timezone and unmarshal from either a numeric epoch or an RFC3339 string, so a value round-trips cleanly. The zero value stays the numeric 0 sentinel (never a 1970 date) and is dropped by omitempty.

inc := list.Items[0]
fmt.Println(inc.StartTime)          // 2026-05-30T14:37:11+08:00  (String / fmt / TOON)
b, _ := json.Marshal(inc.StartTime) // "2026-05-30T14:37:11+08:00"
epoch := inc.StartTime.Unix()       // 1779514631  (raw wire value)
t := inc.StartTime.Time()           // time.Time

Request time fields stay plain int64 — the API expects a numeric epoch on the wire (note: most endpoints take seconds, but RUM and webhook-history endpoints take milliseconds).

Retries

Automatic retries are not built into the core. Compose them at the transport layer with the optional retry subpackage — a safe-by-default retrying http.RoundTripper (retries 429 and 5xx, honors Retry-After, deterministic exponential backoff, and only replays requests whose body is replayable, which all SDK requests are):

import "github.com/flashcatcloud/go-flashduty/retry"

client, err := flashduty.NewClient("YOUR_APP_KEY",
	flashduty.WithTransport(retry.New(
		retry.WithMaxRetries(3),
	)),
)

Development

The typed service layer (services_gen.go, models_gen.go) is generated from the OpenAPI spec vendored in openapi/. Don't edit the generated files; change the spec or the generator in internal/cmd/gen.

make sync-spec   # refresh openapi/ from flashduty-docs
make generate    # regenerate the typed service layer
make check       # fmt, lint, test, build
make e2e         # live end-to-end tests; needs FLASHDUTY_E2E_APP_KEY (optional FLASHDUTY_E2E_BASE_URL)

End-to-end tests create resources with a gofd-e2e- prefix and delete them on cleanup; they never modify existing data.

Related projects

License

Apache-2.0

About

Official Go client (SDK) for the Flashduty Open API — thin, typed, full endpoint coverage

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages