Help us shape the future of Go! Take the 2026 Go Developer Survey

itoc360

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

README

ITOC360 Go SDK

Go Reference Test License

Go client for the ITOC360 Events API.

ITOC360 is an incident management and on-call platform. This SDK sends events to an ITOC360 source, which runs them through your escalation policies, on-call schedules and notification channels — SMS, voice calls, email and push.

Zero dependencies outside the standard library.

Installation

go get github.com/itoc360/itoc360-go

Requires Go 1.22 or later.

Quick start

package main

import (
	"context"
	"log"
	"os"

	"github.com/itoc360/itoc360-go"
)

func main() {
	client, err := itoc360.NewClient(os.Getenv("ITOC360_TOKEN"))
	if err != nil {
		log.Fatal(err)
	}

	_, err = client.SendAlert(context.Background(), itoc360.Alert{
		Fingerprint: "db-primary-disk-full",
		Summary:     "Disk usage on db-primary is at 95%",
		Severity:    itoc360.SeverityCritical,
		Status:      itoc360.StatusFiring,
	})
	if err != nil {
		log.Fatal(err)
	}
}

Authentication

Every request carries a source token. Create a source in the ITOC360 app, choose its provider type, and copy the token it generates. The token identifies both the organization the events belong to and the payload format the endpoint expects.

The SDK sends it as an RFC 6750 bearer token. Read it from the environment or a secret store — never commit it, and never put it in a URL.

Sending alerts

SendAlert takes a provider-independent Alert and expands it into the Prometheus Alertmanager webhook payload:

alert := itoc360.Alert{
	Fingerprint: "db-primary-disk-full",
	Summary:     "Disk usage on db-primary is at 95%",
	Description: "The data volume has less than 5% free space left.",
	Severity:    itoc360.SeverityCritical,
	Status:      itoc360.StatusFiring,
	Labels: map[string]string{
		"instance": "db-01",
		"service":  "payments",
	},
}

resp, err := client.SendAlert(ctx, alert)

Resolve it later by sending the same fingerprint with StatusResolved:

_, err = client.SendAlert(ctx, itoc360.Alert{
	Fingerprint: "db-primary-disk-full",
	Summary:     "Disk usage on db-primary is back to normal",
	Status:      itoc360.StatusResolved,
})
Fingerprints

Fingerprint is the deduplication key. ITOC360 groups every event carrying the same fingerprint into one alert, so an event whose fingerprint matches an open alert updates it instead of paging someone again.

Derive it from whatever makes the condition unique — the host, the check and the object it watches — and keep it identical between the firing and the resolved event. A value that changes per run raises a new alert every time.

Severity

Severity becomes the alert's priority in ITOC360:

Severity Priority
SeverityCritical CRITICAL
SeverityError HIGH
SeverityWarning MEDIUM
SeverityInfo LOW

Defaults to SeverityWarning when unset.

Which sources SendAlert works with

SendAlert produces the Alertmanager payload, so the source must be configured for a provider that speaks it:

prometheus · mimir · cortex · loki · signoz · grafana

Other providers

ITOC360 supports over forty providers, each expecting its own vendor payload — Datadog, Zabbix, Dynatrace, CloudWatch, Splunk and the rest. SendRaw sends any value that marshals to JSON and imposes no shape of its own:

_, err := client.SendRaw(ctx, map[string]any{
	"alert_id":         "42",
	"alert_transition": "Triggered",
	"alert_title":      "CPU high on web-03",
	"alert_type":       "error",
})

Match the payload to the provider your source is configured for; see the ITOC360 documentation for each format.

Configuration

client, err := itoc360.NewClient(token,
	itoc360.WithBaseURL("https://itoc360.internal.example"),
	itoc360.WithHTTPClient(&http.Client{Timeout: 10 * time.Second}),
	itoc360.WithUserAgent("acme-pager/2.1"),
)
Option Purpose
WithBaseURL Point at a self-hosted deployment or a test server
WithHTTPClient Supply your own timeouts, proxy, transport or instrumentation
WithUserAgent Identify your application in ITOC360's request logs

The default base URL is https://api.itoc360.app and the default timeout is 30 seconds.

Error handling

A rejected request returns an *APIError carrying the status and the server's own message. Neither the token nor any request header ever appears in it.

_, err := client.SendAlert(ctx, alert)

var apiErr *itoc360.APIError
switch {
case errors.As(err, &apiErr) && apiErr.Unauthorized():
	// The token is missing or matches no source.
case errors.As(err, &apiErr) && apiErr.SubscriptionInactive():
	// The organization's ITOC360 subscription has lapsed; the event was dropped.
case errors.As(err, &apiErr) && apiErr.Retryable():
	// A server-side failure — worth sending again.
case err != nil:
	log.Printf("sending alert: %v", err)
}

An Alert missing its fingerprint or summary is rejected locally with a *ValidationError, before any request is made.

Development

go test ./...
go vet ./...

The tests run entirely against net/http/httptest and never contact ITOC360.

License

Apache License 2.0. Copyright 2026 ITOC360 INC. See LICENSE.

Documentation

Overview

Package itoc360 is the Go client for the ITOC360 Events API.

ITOC360 is an incident management and on-call platform. This package sends events to an ITOC360 source, which then runs them through the tenant's escalation policies, on-call schedules and notification channels.

Authentication

Every request is authenticated with a source token. A source is created in the ITOC360 web application; each one carries its own token and is bound to a single provider type. The token is sent as an RFC 6750 bearer token.

client, err := itoc360.NewClient(os.Getenv("ITOC360_TOKEN"))
if err != nil {
	return err
}

Sending alerts

Client.SendAlert takes a provider-independent Alert and expands it into the Prometheus Alertmanager webhook payload. It works with any source whose provider speaks that format: prometheus, mimir, cortex, loki, signoz and grafana.

_, err = client.SendAlert(ctx, itoc360.Alert{
	Fingerprint: "db-primary-disk-full",
	Summary:     "Disk usage on db-primary is at 95%",
	Severity:    itoc360.SeverityCritical,
	Status:      itoc360.StatusFiring,
})

Fingerprint is the deduplication key. ITOC360 groups every event carrying the same fingerprint into one alert, so send the same value for the firing and the resolved event, and a different value for an unrelated alert.

Sending other payloads

A source configured for a different provider — Datadog, Zabbix, Dynatrace and so on — expects that vendor's own payload. Client.SendRaw sends any value that marshals to JSON, leaving the shape entirely to the caller.

_, err = client.SendRaw(ctx, map[string]any{"alert_id": "42"})

Index

Examples

Constants

View Source
const (
	// DefaultBaseURL is the ITOC360 API endpoint used unless WithBaseURL says
	// otherwise.
	DefaultBaseURL = "https://api.itoc360.app"

	// Version is the version of this SDK. It is the fallback for the
	// User-Agent header when the build carries no module version, which is
	// the case while developing on this module itself.
	Version = "0.1.0"
)

Variables

View Source
var ErrMissingToken = errors.New("itoc360: source token is required")

ErrMissingToken is returned by NewClient when the source token is empty.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	// StatusCode is the HTTP status returned by ITOC360.
	StatusCode int
	// Message is the server-supplied explanation.
	Message string
}

APIError is returned when ITOC360 responds with a non-2xx status.

Message carries the server's own explanation when the response body is the documented {"error": "..."} object, and a short generic description otherwise. Neither the source token nor any request header is ever included.

Example

Tell the failure modes apart when a send is rejected.

package main

import (
	"context"
	"errors"
	"log"
	"os"

	"github.com/itoc360/itoc360-go"
)

func main() {
	client, err := itoc360.NewClient(os.Getenv("ITOC360_TOKEN"))
	if err != nil {
		log.Fatal(err)
	}

	_, err = client.SendAlert(context.Background(), itoc360.Alert{
		Fingerprint: "db-primary-disk-full",
		Summary:     "Disk usage on db-primary is at 95%",
	})

	var apiErr *itoc360.APIError
	switch {
	case err == nil:
		return
	case errors.As(err, &apiErr) && apiErr.Unauthorized():
		log.Fatal("ITOC360_TOKEN is not a valid source token")
	case errors.As(err, &apiErr) && apiErr.SubscriptionInactive():
		log.Fatal("the ITOC360 subscription for this organization is not active")
	case errors.As(err, &apiErr) && apiErr.Retryable():
		log.Printf("ITOC360 is unavailable, will retry: %v", apiErr)
	default:
		log.Printf("sending alert: %v", err)
	}
}

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Retryable

func (e *APIError) Retryable() bool

Retryable reports whether the request is worth sending again unchanged. Server-side failures, rate limiting and a timed-out request are; a rejected payload is not.

func (*APIError) SubscriptionInactive

func (e *APIError) SubscriptionInactive() bool

SubscriptionInactive reports whether the tenant's ITOC360 subscription has lapsed. ITOC360 answers 402 in that case and drops the event.

func (*APIError) Unauthorized

func (e *APIError) Unauthorized() bool

Unauthorized reports whether the token was missing or not recognised.

ITOC360 answers 401 when no token is presented and 404 when the token matches no source, so both are treated as credential failures. Telling that 404 apart from a genuinely missing resource means reading the server's wording; should ITOC360 rephrase it, this method stops recognising the case but StatusCode and Message still describe what happened.

type Alert

type Alert struct {
	// Fingerprint identifies the alert across its lifetime and is required.
	//
	// ITOC360 deduplicates on this value: an event whose fingerprint matches
	// an open alert updates that alert instead of raising a new one. Derive it
	// from what makes the condition unique — the host, the check and the
	// object it watches, say — and keep it stable between the firing and the
	// resolved event.
	Fingerprint string

	// Summary is the one-line description shown as the alert's title in
	// ITOC360 and in the notifications it sends. It is required.
	Summary string

	// Description is optional longer text shown alongside the summary.
	Description string

	// Severity sets the alert's priority. Defaults to SeverityWarning.
	Severity Severity

	// Status says whether the alert is firing or resolved. Defaults to
	// StatusFiring.
	Status Status

	// Labels are arbitrary key-value pairs describing the alert, such as the
	// instance or the service it concerns. Escalation rules can match on them.
	//
	// A "severity" key is added from the Severity field; an explicit entry
	// here does not override it.
	Labels map[string]string

	// Annotations are additional key-value pairs carried with the alert.
	// "summary" and "description" are filled in from the fields above.
	Annotations map[string]string

	// StartsAt is when the condition began. Defaults to the current time.
	StartsAt time.Time

	// EndsAt is when the condition cleared. It is sent only for resolved
	// alerts, where it defaults to the current time.
	EndsAt time.Time

	// GeneratorURL optionally links back to whatever raised the alert — a
	// dashboard, a run, a log query.
	GeneratorURL string

	// Receiver names the sender in the stored payload. Defaults to
	// "itoc360-go".
	Receiver string
}

Alert is a single alert to send to ITOC360.

Fingerprint and Summary are required. Status defaults to StatusFiring, Severity to SeverityWarning and StartsAt to the current time.

func (Alert) Validate

func (a Alert) Validate() error

Validate reports whether the alert can be sent. Client.SendAlert calls it before every request, so calling it directly is only useful to check user input early.

Example

Check user input before a send. SendAlert runs the same check itself, so this is only worth doing to report the problem earlier.

package main

import (
	"errors"
	"log"

	"github.com/itoc360/itoc360-go"
)

func main() {
	alert := itoc360.Alert{Summary: "Disk usage on db-primary is at 95%"}

	var verr *itoc360.ValidationError
	if err := alert.Validate(); errors.As(err, &verr) {
		log.Printf("alert field %s is not usable: %s", verr.Field, verr.Message)
	}
}

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client sends events to a single ITOC360 source. It is safe for concurrent use by multiple goroutines.

func NewClient

func NewClient(token string, opts ...Option) (*Client, error)

NewClient returns a Client that authenticates with the given ITOC360 source token. It returns ErrMissingToken if the token is empty.

The token is created alongside a source in the ITOC360 web application and determines which tenant the events belong to and which payload format the endpoint expects. Read it from the environment or a secret store; never commit it.

Example

Create a client from a source token held in the environment.

package main

import (
	"log"
	"os"

	"github.com/itoc360/itoc360-go"
)

func main() {
	client, err := itoc360.NewClient(os.Getenv("ITOC360_TOKEN"))
	if err != nil {
		log.Fatal(err)
	}

	_ = client
}
Example (Options)

Configure the client for a self-hosted deployment and a tighter timeout.

package main

import (
	"log"
	"net/http"
	"os"
	"time"

	"github.com/itoc360/itoc360-go"
)

func main() {
	client, err := itoc360.NewClient(
		os.Getenv("ITOC360_TOKEN"),
		itoc360.WithBaseURL("https://itoc360.internal.example"),
		itoc360.WithHTTPClient(&http.Client{Timeout: 10 * time.Second}),
		itoc360.WithUserAgent("acme-pager/2.1"),
	)
	if err != nil {
		log.Fatal(err)
	}

	_ = client
}

func (*Client) SendAlert

func (c *Client) SendAlert(ctx context.Context, alert Alert) (*EventResponse, error)

SendAlert sends an alert to ITOC360.

The alert is expanded into the Prometheus Alertmanager webhook payload, so the source must be configured for a provider that speaks it: prometheus, mimir, cortex, loki, signoz or grafana. For any other provider, build that vendor's payload and use SendRaw.

A ValidationError is returned, without contacting ITOC360, when the alert is missing a fingerprint or a summary.

Example

Raise an alert. The fingerprint is what ITOC360 deduplicates on, so derive it from the condition rather than generating one per run.

package main

import (
	"context"
	"log"
	"os"

	"github.com/itoc360/itoc360-go"
)

func main() {
	client, err := itoc360.NewClient(os.Getenv("ITOC360_TOKEN"))
	if err != nil {
		log.Fatal(err)
	}

	event, err := client.SendAlert(context.Background(), itoc360.Alert{
		Fingerprint: "db-primary-disk-full",
		Summary:     "Disk usage on db-primary is at 95%",
		Description: "The data volume has less than 5% free space left.",
		Severity:    itoc360.SeverityCritical,
		Status:      itoc360.StatusFiring,
		Labels: map[string]string{
			"instance": "db-01",
			"service":  "payments",
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("raised alert %s (%s)", event.ID, event.Type)
}
Example (Resolve)

Close an alert by sending the same fingerprint with StatusResolved.

package main

import (
	"context"
	"log"
	"os"

	"github.com/itoc360/itoc360-go"
)

func main() {
	client, err := itoc360.NewClient(os.Getenv("ITOC360_TOKEN"))
	if err != nil {
		log.Fatal(err)
	}

	_, err = client.SendAlert(context.Background(), itoc360.Alert{
		Fingerprint: "db-primary-disk-full",
		Summary:     "Disk usage on db-primary is back to normal",
		Status:      itoc360.StatusResolved,
	})
	if err != nil {
		log.Fatal(err)
	}
}

func (*Client) SendRaw

func (c *Client) SendRaw(ctx context.Context, payload any) (*EventResponse, error)

SendRaw sends payload to ITOC360 as the event body, marshalled as JSON.

It applies no shape of its own, so it works with every provider ITOC360 supports: pass the payload that provider documents. Use SendAlert instead when the source speaks the Alertmanager format.

Example

Send a vendor payload to a source configured for a provider other than the Alertmanager family — here, Datadog.

package main

import (
	"context"
	"log"
	"os"

	"github.com/itoc360/itoc360-go"
)

func main() {
	client, err := itoc360.NewClient(os.Getenv("ITOC360_TOKEN"))
	if err != nil {
		log.Fatal(err)
	}

	_, err = client.SendRaw(context.Background(), map[string]any{
		"alert_id":         "42",
		"alert_transition": "Triggered",
		"alert_title":      "CPU high on web-03",
		"alert_type":       "error",
	})
	if err != nil {
		log.Fatal(err)
	}
}

type EventResponse

type EventResponse struct {
	// ID is the identifier of the stored event.
	ID string `json:"id"`
	// TenantID is the organization the source belongs to.
	TenantID string `json:"tenant_id"`
	// ProviderID is the provider the source is configured for.
	ProviderID int64 `json:"provider_id"`
	// SourceID is the source the token resolved to.
	SourceID string `json:"source_id"`
	// Type is "ALERT" for a firing event and "RESOLVE" for a resolved one.
	Type string `json:"type"`
	// Fingerprint is the deduplication key ITOC360 derived from the payload.
	Fingerprint string `json:"fingerprint"`
	// Payload is the body as ITOC360 stored it.
	Payload json.RawMessage `json:"payload"`
	// CreatedAt is when the event was recorded.
	CreatedAt time.Time `json:"created_at"`
}

EventResponse is the event ITOC360 recorded, returned on success.

type Option

type Option func(*Client)

Option configures a Client. Options are applied by NewClient in the order they are given.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL points the client at a different ITOC360 deployment. Use it for self-hosted installations and for tests. A trailing slash is ignored.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient supplies the http.Client used for requests, which is where timeouts, proxies, transports and instrumentation belong. The default client has a 30 second timeout.

func WithUserAgent

func WithUserAgent(userAgent string) Option

WithUserAgent replaces the User-Agent header. The default identifies this SDK and its version; prefer appending to it over replacing it.

type Severity

type Severity string

Severity is the urgency of an alert. ITOC360 maps it to the alert's priority: critical to CRITICAL, error to HIGH, warning to MEDIUM and info to LOW.

const (
	SeverityCritical Severity = "critical"
	SeverityError    Severity = "error"
	SeverityWarning  Severity = "warning"
	SeverityInfo     Severity = "info"
)

Severities recognised by ITOC360. Any other value leaves the alert without a priority.

type Status

type Status string

Status says whether an alert is starting or ending.

const (
	StatusFiring   Status = "firing"
	StatusResolved Status = "resolved"
)

Statuses recognised by ITOC360. StatusFiring opens or updates an alert and StatusResolved closes it. No other value is accepted.

type ValidationError

type ValidationError struct {
	// Field is the name of the offending Alert field.
	Field string
	// Message explains what is wrong with it.
	Message string
}

ValidationError is returned when an Alert cannot be sent as written. The request is rejected locally and never reaches ITOC360.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Directories

Path Synopsis
examples
basic command
Command basic sends one alert to ITOC360 and then resolves it.
Command basic sends one alert to ITOC360 and then resolves it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL