webhook

package
v0.62.1 Latest Latest
Warning

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

Go to latest
Published: Aug 16, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package webhook delivers outbound notifications to operator-configured URLs (used by alerts and the daily digest). Two delivery contracts: HMAC-signed JSON for generic endpoints, and Slack's {"text": ...} shape for Slack incoming webhooks (which reject anything else). Persisted store, best-effort async delivery.

Index

Constants

View Source
const (
	// FormatSlack — {"text": "<plain-text rendering>"}. Also matches Mattermost and Rocket.Chat,
	// both of which implement Slack's incoming-webhook contract deliberately.
	FormatSlack = "slack"
	// FormatDiscord — {"content": ...}. Discord 400s on {"text": ...}, so a Discord URL pasted
	// into the webhook box was rejected on every single delivery, forever, silently: the send is
	// fire-and-forget, so the failure went nowhere. Discord is where this ICP actually is, which
	// made it the most expensive missing line in the file.
	FormatDiscord = "discord"
)

Chat formats. Each is a receiver that will NOT accept our signed-JSON contract: it wants its own tiny envelope and rejects anything else, so an endpoint on one of these hosts gets the human rendering and no signature (there is nowhere to put one).

Variables

This section is empty.

Functions

func Send

func Send(ep Endpoint, body []byte, text string) (int, error)

Send POSTs one delivery to an endpoint and returns the HTTP status the endpoint answered with (0 when no response arrived). Slack-format endpoints receive {"text": text} — Slack rejects any other body shape and cannot verify signature headers — while every other endpoint keeps the signed-JSON contract unchanged: the body verbatim plus X-Smolanalytics-Signature. text is the plain-text rendering of body; if a caller passes none, the raw JSON body is used as the text so a Slack message still carries the facts instead of failing.

func SendTest added in v0.8.0

func SendTest(ep Endpoint) (int, error)

SendTest fires a synthetic delivery through the exact path real alerts and digests take (same format rules, signing, SSRF guard, and HTTP client), so a 2xx here means real deliveries will land. Returns the endpoint's HTTP status. Shared by POST /v1/webhooks/{id}/test and the MCP test_webhook tool.

Types

type Endpoint

type Endpoint struct {
	ID      string    `json:"id"`
	Name    string    `json:"name"`
	URL     string    `json:"url"`
	Secret  string    `json:"secret"` // signs the payload so the receiver can verify
	Format  string    `json:"format,omitempty"`
	Enabled bool      `json:"enabled"`
	Created time.Time `json:"created"`
}

Endpoint is one registered webhook target.

func (Endpoint) Chat added in v0.60.0

func (e Endpoint) Chat() bool

Chat reports whether this endpoint takes a chat envelope rather than signed JSON.

func (Endpoint) DiscordFormat added in v0.60.0

func (e Endpoint) DiscordFormat() bool

DiscordFormat reports whether deliveries use Discord's {"content": ...} contract, either because the endpoint says so or because the URL is plainly a Discord webhook — the host check also covers endpoints persisted before this format existed, which is every one of them.

func (Endpoint) SlackFormat added in v0.8.0

func (e Endpoint) SlackFormat() bool

SlackFormat reports whether deliveries to e use Slack's {"text": ...} contract: either the endpoint was created with format "slack", or the URL is a Slack incoming webhook (hooks.slack.com) — the host check also covers endpoints persisted before the format field existed.

type Store

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

func Open

func Open(path string) (*Store, error)

func (*Store) Add

func (s *Store) Add(name, url, format string) (Endpoint, error)

Add registers a new endpoint. format is "" (auto-detect: Slack contract for hooks.slack.com URLs, signed JSON for everything else) or "slack" to force the Slack text contract for Slack-compatible receivers on other hosts (Mattermost, Rocket.Chat, …).

func (*Store) Delete

func (s *Store) Delete(id string) (found bool, err error)

Delete removes an endpoint by id. found is true only when an endpoint actually went away, so callers never claim a removal that did not occur. A miss is not an error.

func (*Store) DeliverAll

func (s *Store) DeliverAll(payload any, text string)

DeliverAll fires the payload to every enabled endpoint, async + best-effort. text is the plain-text rendering that Slack-format endpoints receive.

func (*Store) Get

func (s *Store) Get(id string) (Endpoint, bool)

func (*Store) List

func (s *Store) List() []Endpoint

Jump to

Keyboard shortcuts

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