hey

package
v0.28.0 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package hey provides a Go SDK for the HEY API.

The SDK handles authentication, HTTP caching, rate limiting, and retry logic. It supports both OAuth 2.0 authentication and static token authentication.

Installation

To install the SDK, use go get:

go get github.com/basecamp/hey-sdk/go/pkg/hey

Authentication

The SDK supports two authentication methods:

Static Token Authentication (simplest):

cfg := hey.DefaultConfig()
token := &hey.StaticTokenProvider{Token: os.Getenv("HEY_TOKEN")}
client := hey.NewClient(cfg, token)

OAuth 2.0 Authentication (for user-facing apps):

cfg := hey.DefaultConfig()
authMgr := hey.NewAuthManager(cfg, http.DefaultClient)
client := hey.NewClient(cfg, authMgr)

Services

The SDK provides typed services for each HEY resource:

Linked Accounts and Separate Identities

A root client represents one authenticated HEY identity and presents mail from All Accounts. Client.ForAccount derives an immutable client that presents mail and resolves acting senders and users for one linked account:

work, err := client.ForAccount(ctx, workAccountID)
if err != nil {
    log.Fatal(err)
}
postings, err := work.Boxes().GetImbox(ctx, nil)

Separate identities use separate root clients with their own token providers or authentication strategies. Each root client can derive its own linked account clients.

Account scope follows HEY's mail-filter semantics and is not an authorization boundary. Identity-owned services such as Calendar and Journal remain identity-wide.

Working with Boxes

List all mailboxes:

boxes, err := client.Boxes().List(ctx)
if err != nil {
    log.Fatal(err)
}
for _, b := range boxes {
    fmt.Println(b.Name)
}

Pagination

The SDK handles pagination automatically via FollowPagination:

resp, err := client.Contacts().List(ctx, nil)
// The SDK follows Link headers for pagination

Error Handling

The SDK returns typed errors that can be inspected:

_, err := client.Boxes().Get(ctx, 999)
if err != nil {
    var apiErr *hey.Error
    if errors.As(err, &apiErr) {
        switch apiErr.Code {
        case hey.CodeNotFound:
            // Handle 404
        case hey.CodeAuth:
            // Handle authentication error
        case hey.CodeRateLimit:
            // Handle rate limiting (auto-retried by default)
        }
    }
}

JSON and HTML response bodies are capped in the transport at WithMaxResponseBodyBytes (16 MiB of decompressed body by default), success and error responses alike. A body past the cap fails with an error that wraps ErrResponseTooLarge and is not retried; a refused error response still carries its status in the Error the read fails with. Buffered blob and CSV answers (Client.GetBlob, Client.GetCSV) are bounded by the 50 MiB MaxResponseBodyBytes constant instead; only Client.DownloadBlob reads without a bound.

Thread Safety

The Client is safe for concurrent use after construction. Service accessors (e.g., client.Boxes()) use mutex-protected lazy initialization.

Index

Constants

View Source
const (
	ClearanceApproved = "approved"
	ClearanceDenied   = "denied"
)

ClearanceApproved and ClearanceDenied are the two screener decisions the API accepts.

View Source
const (
	CodeUsage      = "usage"
	CodeNotFound   = "not_found"
	CodeAuth       = "auth_required"
	CodeForbidden  = "forbidden"
	CodeRateLimit  = "rate_limit"
	CodeNetwork    = "network"
	CodeAPI        = "api_error"
	CodeValidation = "validation"
	CodeAmbiguous  = "ambiguous"
	CodeConflict   = "conflict"
)

Error codes for API responses.

View Source
const (
	ExitOK         = 0 // Success
	ExitUsage      = 1 // Invalid arguments or flags
	ExitNotFound   = 2 // Resource not found
	ExitAuth       = 3 // Not authenticated
	ExitForbidden  = 4 // Access denied (scope issue)
	ExitRateLimit  = 5 // Rate limited (429)
	ExitNetwork    = 6 // Connection/DNS/timeout error
	ExitAPI        = 7 // Server returned error
	ExitAmbiguous  = 8 // Multiple matches for name
	ExitValidation = 9 // Validation error (422)
)

Exit codes for CLI tools.

View Source
const (
	DefaultMaxRetries = 3
	DefaultBaseDelay  = 1 * time.Second
	DefaultMaxJitter  = 100 * time.Millisecond
	DefaultTimeout    = 30 * time.Second
	DefaultMaxPages   = 10000

	// DefaultMaxResponseBodyBytes is the most a JSON or HTML response may deliver, in
	// decompressed bytes: 16 MiB, which is a message with a very large HTML body several
	// times over, and small enough that a server answering one page with gigabytes is
	// refused long before it exhausts memory.
	DefaultMaxResponseBodyBytes int64 = 16 << 20
)

Default values for HTTP client configuration.

View Source
const (
	BoxKindImbox    = "imbox"
	BoxKindFeed     = "feedbox"
	BoxKindSetAside = "asidebox"
	BoxKindLater    = "laterbox"
	BoxKindTrail    = "trailbox"
	BoxKindBubbleUp = "bubblebox"
)

Box kinds as reported by ListBoxes. Use with MoveToBox.

View Source
const (
	// MaxResponseBodyBytes is the most the client buffers of a successful body the
	// transport cap leaves alone — a blob read with GetBlob, an export read with GetCSV, a
	// mutation answered to a */* request, a form or multipart answer — 50 MiB. Only
	// DownloadBlob, which streams to the caller's writer, reads without a bound. A body
	// past it fails with an error wrapping ErrResponseTooLarge.
	//
	// This constant shares its name with the HTTPOptions.MaxResponseBodyBytes field and is
	// not the same limit: the field is the configurable cap on JSON and HTML, this is the
	// fixed bound on everything else. The name predates the field and is kept for
	// compatibility.
	MaxResponseBodyBytes int64 = 50 * 1024 * 1024
	// MaxErrorBodyBytes is the maximum size for error response bodies (1 MB).
	MaxErrorBodyBytes int64 = 1 * 1024 * 1024
	// MaxErrorMessageBytes is the maximum length for error messages included in errors (500 bytes).
	MaxErrorMessageBytes = 500
)

Response body size limits. JSON and HTML answers are capped in the transport, at the client's configured limit (HTTPOptions.MaxResponseBodyBytes, WithMaxResponseBodyBytes; DefaultMaxResponseBodyBytes, 16 MiB, by default), before any of these apply.

View Source
const (
	StickySmall  = "small"
	StickyMedium = "medium"
	StickyLarge  = "large"
)

Sticky sizes the API accepts.

View Source
const APIVersion = "2026-08-21"

APIVersion is the HEY API version this SDK targets.

View Source
const DefaultUserAgent = "hey-sdk-go/" + Version + " (api:" + APIVersion + ")"

DefaultUserAgent is the default User-Agent header value.

View Source
const MaxStickiesLimit = 100

MaxStickiesLimit is the largest page the stickies index answers with. The server clamps anything above it, so List clamps too rather than sending a number it knows is ignored.

View Source
const MaxStickyPosition = math.MaxInt32

MaxStickyPosition is the highest board position Move accepts. The wire format carries the position as a 32-bit integer.

View Source
const Version = "0.28.0"

Version is the current version of the HEY Go SDK.

View Source
const WorldAddress = "world@hey.com"

WorldAddress is the recipient that turns a message into a HEY World post.

Variables

View Source
var (
	// ErrCircuitOpen is returned when the circuit breaker is open.
	ErrCircuitOpen = errors.New("circuit breaker is open")
	// ErrBulkheadFull is returned when the bulkhead has no available slots.
	ErrBulkheadFull = errors.New("bulkhead is full")
	// ErrRateLimited is returned when the rate limiter rejects a request.
	ErrRateLimited = errors.New("rate limit exceeded")
)

Resilience errors for circuit breaker, bulkhead, and rate limiting.

View Source
var ErrResponseTooLarge = errors.New("response body exceeded the size limit")

ErrResponseTooLarge is the error a response body ends with once it passes the bound it reads under: a JSON or HTML body, success or error alike, at the client's configured MaxResponseBodyBytes (HTTPOptions, WithMaxResponseBodyBytes), and a buffered blob, export, form or multipart answer at the 50 MiB MaxResponseBodyBytes constant. It reaches the caller wrapped, so test for it with errors.Is. An error response refused this way still carries its status: the error is the *Error CheckResponse builds for the status, with the refusal as its Cause, so errors.As finds the HTTPStatus and errors.Is finds this. The refusal reaches whoever reads the body. The generated parsers read every body, so a service method answers with it; the raw Get and GetHTML answer an error status without reading its body, so there the status error stands alone and the oversized body is simply never buffered — which is what the bound is for.

Functions

func CheckResponse

func CheckResponse(resp *http.Response) error

CheckResponse converts HTTP response errors to SDK errors for non-2xx responses. It is exported for use by conformance testing and consumers using the raw generated client.

func ExitCodeFor

func ExitCodeFor(code string) int

ExitCodeFor returns the exit code for a given error code.

func NormalizeBaseURL

func NormalizeBaseURL(url string) string

NormalizeBaseURL ensures consistent URL format (no trailing slash).

func RedactHeaders

func RedactHeaders(headers http.Header) http.Header

RedactHeaders returns a copy of the headers with sensitive values replaced by "[REDACTED]".

func RequireSecureEndpoint

func RequireSecureEndpoint(rawURL string) error

RequireSecureEndpoint validates that an endpoint URL is secure.

func UndoSendID added in v0.4.0

func UndoSendID(undoSendURL string) (int64, error)

UndoSendID reads the bulk reply id out of a delivery's undo URL, for callers holding the URL rather than the delivery.

Types

type AttachmentsService added in v0.5.0

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

AttachmentsService handles outgoing attachment uploads.

func NewAttachmentsService added in v0.5.0

func NewAttachmentsService(client *Client) *AttachmentsService

NewAttachmentsService creates an AttachmentsService.

func (*AttachmentsService) CreateDirectUpload added in v0.5.0

CreateDirectUpload creates an Active Storage blob and returns the target for uploading its bytes. The target URL is self-authenticating and must be used with the exact headers returned by HEY.

func (*AttachmentsService) Upload added in v0.5.0

func (s *AttachmentsService) Upload(ctx context.Context, filename, contentType string, content io.ReadSeeker) (*generated.DirectUpload, error)

Upload reserves an Active Storage blob and uploads the supplied bytes to its self-authenticating storage URL. The returned attachment can be embedded in rich text with its AttachableSgid.

type AuthManager

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

AuthManager handles OAuth token management.

func NewAuthManager

func NewAuthManager(cfg *Config, httpClient *http.Client) *AuthManager

NewAuthManager creates a new auth manager.

func NewAuthManagerWithStore

func NewAuthManagerWithStore(cfg *Config, httpClient *http.Client, store *CredentialStore) *AuthManager

NewAuthManagerWithStore creates an auth manager with a custom credential store.

func (*AuthManager) AccessToken

func (m *AuthManager) AccessToken(ctx context.Context) (string, error)

AccessToken returns a valid access token, refreshing if needed.

func (*AuthManager) GetUserID

func (m *AuthManager) GetUserID() string

GetUserID returns the stored user ID.

func (*AuthManager) IsAuthenticated

func (m *AuthManager) IsAuthenticated() bool

IsAuthenticated checks if there are valid credentials.

func (*AuthManager) Logout

func (m *AuthManager) Logout() error

Logout removes stored credentials.

func (*AuthManager) Refresh

func (m *AuthManager) Refresh(ctx context.Context) error

Refresh forces a token refresh.

func (*AuthManager) SetUserID

func (m *AuthManager) SetUserID(userID string) error

SetUserID stores the user ID.

func (*AuthManager) Store

func (m *AuthManager) Store() *CredentialStore

Store returns the credential store.

type AuthStrategy

type AuthStrategy interface {
	// Authenticate applies authentication to the given HTTP request.
	Authenticate(ctx context.Context, req *http.Request) error
}

AuthStrategy controls how authentication is applied to HTTP requests. The default strategy is BearerAuth, which uses a TokenProvider to set the Authorization header with a Bearer token.

type BearerAuth

type BearerAuth struct {
	TokenProvider TokenProvider
}

BearerAuth implements AuthStrategy using OAuth Bearer tokens. This is the default authentication strategy.

func (*BearerAuth) Authenticate

func (b *BearerAuth) Authenticate(ctx context.Context, req *http.Request) error

Authenticate sets the Authorization header with a Bearer token.

type BoxPage added in v0.10.0

type BoxPage struct {
	Box        *generated.BoxShowResponse
	NextPage   string
	TotalCount int
}

BoxPage contains one page of a box and its pagination state.

type BoxesService

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

BoxesService handles mailbox operations.

func NewBoxesService

func NewBoxesService(client *Client) *BoxesService

NewBoxesService creates a new BoxesService.

func (*BoxesService) CreateGroup added in v0.4.0

func (s *BoxesService) CreateGroup(ctx context.Context, boxID int64, postingIDs []int64) (result *generated.BoxGroup, err error)

CreateGroup gathers a selection of postings into a new Set Aside group.

func (*BoxesService) DeleteGroup added in v0.4.0

func (s *BoxesService) DeleteGroup(ctx context.Context, boxID int64, groupID int64) error

DeleteGroup breaks up a Set Aside group, sending its postings back to Previously Seen.

func (*BoxesService) Get

Get returns a specific mailbox by ID.

func (*BoxesService) GetAsidebox

func (s *BoxesService) GetAsidebox(ctx context.Context, params *generated.GetAsideboxParams) (result *generated.BoxShowResponse, err error)

GetAsidebox returns the Set Aside box.

func (*BoxesService) GetBubblebox

func (s *BoxesService) GetBubblebox(ctx context.Context, params *generated.GetBubbleboxParams) (result *generated.BoxShowResponse, err error)

GetBubblebox returns the Bubbled Up box.

func (*BoxesService) GetFeedbox

func (s *BoxesService) GetFeedbox(ctx context.Context, params *generated.GetFeedboxParams) (result *generated.BoxShowResponse, err error)

GetFeedbox returns the Feed.

func (*BoxesService) GetImbox

func (s *BoxesService) GetImbox(ctx context.Context, params *generated.GetImboxParams) (result *generated.BoxShowResponse, err error)

GetImbox returns the Imbox.

func (*BoxesService) GetImboxSeen added in v0.28.0

func (s *BoxesService) GetImboxSeen(ctx context.Context, params *generated.GetImboxSeenParams) (result *generated.BoxShowResponse, err error)

GetImboxSeen returns the Imbox's Previously Seen postings, ordered by when they were seen (observed_at desc). The response's next_history_url names the /imbox route, but its page cursor belongs to the seen scope — extract the cursor and feed it back to GetImboxSeen, never to GetImbox.

func (*BoxesService) GetLaterbox

func (s *BoxesService) GetLaterbox(ctx context.Context, params *generated.GetLaterboxParams) (result *generated.BoxShowResponse, err error)

GetLaterbox returns the Reply Later box.

func (*BoxesService) GetPage added in v0.10.0

func (s *BoxesService) GetPage(ctx context.Context, boxID int64, params *generated.GetBoxParams) (result *BoxPage, err error)

GetPage returns a box page with its next cursor and total posting count.

func (*BoxesService) GetTrailbox

func (s *BoxesService) GetTrailbox(ctx context.Context, params *generated.GetTrailboxParams) (result *generated.BoxShowResponse, err error)

GetTrailbox returns the Paper Trail.

func (*BoxesService) List

List returns all mailboxes.

func (*BoxesService) ListGroups added in v0.4.0

func (s *BoxesService) ListGroups(ctx context.Context, boxID int64) (result *generated.BoxGroupsResponse, err error)

ListGroups returns the Set Aside groups in a box. The API answers with ids only.

func (*BoxesService) MarkSeen added in v0.4.0

func (s *BoxesService) MarkSeen(ctx context.Context, boxID int64) error

MarkSeen marks everything in a box as seen. The server queues the work, so postings can still read as unseen right after this returns.

type BubbleUpSlot added in v0.24.0

type BubbleUpSlot string

BubbleUpSlot is one of HEY's named bubble-up schedule slots — the web app's "Later today", "Tomorrow", "This weekend" and "Next week". Later today lands at HEY's evening hour of the current day, the others at its morning hour of their day (Saturday for the weekend, Monday for next week) — in UTC, like every hour HEY reads out of a JSON request.

const (
	BubbleUpLaterToday  BubbleUpSlot = "today"
	BubbleUpTomorrow    BubbleUpSlot = "tomorrow"
	BubbleUpThisWeekend BubbleUpSlot = "weekend"
	BubbleUpNextWeek    BubbleUpSlot = "next_week"
)

type BulkRepliesService added in v0.4.0

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

BulkRepliesService sends one reply to many threads at once.

func NewBulkRepliesService added in v0.4.0

func NewBulkRepliesService(client *Client) *BulkRepliesService

NewBulkRepliesService creates a new BulkRepliesService.

func (*BulkRepliesService) Draft added in v0.4.0

func (s *BulkRepliesService) Draft(ctx context.Context, postingIDs []int64) (draft *generated.BulkReplyDraft, err error)

Draft works out which entries a bulk reply would answer, and how it starts.

HEY replies to the last replyable entry of each thread and skips threads it has no reply address for, so the postings you hold are not the entries the reply goes to. Send the entries this returns — or a subset of them — to Send.

func (*BulkRepliesService) Send added in v0.4.0

func (s *BulkRepliesService) Send(ctx context.Context, entryIDs []int64, content string) (delivery *generated.BulkReplyDelivery, err error)

Send replies to every entry with the same content, and answers what was sent.

Delivery is queued. While the sender has undo enabled the send is held open, and the answer says so: Delayed is true and UndoSendUrl is where to call it back.

func (*BulkRepliesService) Undo added in v0.4.0

func (s *BulkRepliesService) Undo(ctx context.Context, bulkReplyID int64) error

Undo calls back a delayed bulk reply before it goes out. It answers a usage error once the replies have been sent.

HEY answers this one with a redirect rather than JSON — the same response its own apps read — so the SDK follows it instead of decoding a body.

type BulkheadConfig

type BulkheadConfig struct {
	MaxConcurrent int
	MaxWait       time.Duration
}

BulkheadConfig configures concurrency limiting.

func DefaultBulkheadConfig

func DefaultBulkheadConfig() *BulkheadConfig

DefaultBulkheadConfig returns production-ready defaults.

type BundlePage added in v0.26.0

type BundlePage struct {
	Contact  generated.Contact
	Postings []generated.Posting
	NextPage string
}

BundlePage is one page of the unseen postings inside a bundle posting: the bundled contact, the member postings newest first, and the cursor for the page below — empty on the last page.

type Cache

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

Cache provides ETag-based HTTP caching.

func NewCache

func NewCache(dir string) *Cache

NewCache creates a new cache with the given directory.

func (*Cache) Clear

func (c *Cache) Clear() error

Clear removes all cached data.

func (*Cache) GetBody

func (c *Cache) GetBody(key string) []byte

GetBody returns the cached response body for a key, or nil if not found.

func (*Cache) GetETag

func (c *Cache) GetETag(key string) string

GetETag returns the cached ETag for a key, or empty string if not found.

func (*Cache) Invalidate

func (c *Cache) Invalidate(key string) error

Invalidate removes cached data for a specific key.

func (*Cache) Key

func (c *Cache) Key(url, token string) string

Key generates a cache key for a URL and authorization value. Account-scoped request URLs carry their account filter in the query, so each linked account has distinct cache entries.

func (*Cache) Set

func (c *Cache) Set(key string, body []byte, etag string) error

Set stores a response body and ETag for a key.

type CalendarChanges added in v0.21.0

type CalendarChanges struct {
	Added      []ListedCalendar
	Updated    []generated.Calendar
	Deleted    []DeletedCalendar
	NextPage   *CalendarChangesCursor
	NextCursor *CalendarChangesCursor
}

CalendarChanges is everything that happened to the calendar list since a cursor. Added calendars arrive as ListedCalendar, so a new calendar comes with the changes URL and signed stream name a live follower needs.

NextPage is set while this increment has more pages to read now. NextCursor is set on the last page and is where the next read should resume; it is nil when nothing changed, in which case the cursor that produced this page still stands. Unlike the recording feed, this feed never falls too far behind, so there is no FullSyncRequired here.

type CalendarChangesCursor added in v0.21.0

type CalendarChangesCursor struct {
	Since   string
	Version string
	Page    string
	PerPage string
}

CalendarChangesCursor is where a read of a calendar changes feed starts — either the calendar-level feed behind a CalendarList's CalendarChangesURL or a calendar's own recording feed behind its RecordingChangesURL; both speak the same cursor. Since is an ISO 8601 timestamp with milliseconds and is exclusive; Version is the contract version the caller speaks. The two server-issued URLs differ: a recording_changes_url carries v=1, which the recording feed requires, while a calendar_changes_url carries no version at all. The server issues the pair in those URLs to begin with — read them with CalendarChangesCursorFrom rather than picking the query apart.

func CalendarChangesCursorFrom added in v0.21.0

func CalendarChangesCursorFrom(changesURL string) (CalendarChangesCursor, error)

CalendarChangesCursorFrom reads a cursor out of a changes URL the server issued: a CalendarList's CalendarChangesURL, a calendar's RecordingChangesURL, or a Link header either feed answered with. The recording feed refuses a cursor without the version the server put in its URL, so this is the only sound way to build one for it.

type CalendarEventsService added in v0.4.0

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

CalendarEventsService handles calendar event operations.

Calendar events take form-encoded bodies because that is the shape the HEY endpoints parse. Create posts to the .json path, so a current server answers the created recording; a server without the JSON branch redirects instead and only the id comes back. Listing events is done through CalendarsService.GetRecordings.

func NewCalendarEventsService added in v0.4.0

func NewCalendarEventsService(client *Client) *CalendarEventsService

NewCalendarEventsService creates a new CalendarEventsService.

func (*CalendarEventsService) Create added in v0.4.0

func (s *CalendarEventsService) Create(ctx context.Context, params CreateCalendarEventParams) (recording *generated.Recording, err error)

Create creates a new calendar event and returns it as a recording.

A server carrying the JSON create branch answers 201 with the whole recording. An older one redirects to the event instead, and the result then carries only the id.

func (*CalendarEventsService) Delete added in v0.4.0

func (s *CalendarEventsService) Delete(ctx context.Context, eventID int64) (err error)

Delete deletes a calendar event.

func (*CalendarEventsService) DeleteOccurrence added in v0.19.0

func (s *CalendarEventsService) DeleteOccurrence(ctx context.Context, occurrence EventOccurrence, scope OccurrenceScope) (err error)

DeleteOccurrence removes one day of a repeating event, or that day and every one after it.

DELETE /calendar/events/{event id}/occurrences/{YYYY-MM-DD}.json, with the scope in the query string because a delete carries no body. HEY answers 204, so there is nothing to read back: a single day becomes an exception in the series' schedule, and the wider scope truncates the series at the day before — or destroys it, if this was its first day.

func (*CalendarEventsService) Update added in v0.4.0

func (s *CalendarEventsService) Update(ctx context.Context, eventID int64, params UpdateCalendarEventParams) (recording *generated.Recording, err error)

Update updates an existing calendar event and returns it as a recording.

A server carrying the JSON update branch answers 200 with the whole recording. An older one redirects to the event instead, and the result then carries only the id.

func (*CalendarEventsService) UpdateOccurrence added in v0.19.0

func (s *CalendarEventsService) UpdateOccurrence(ctx context.Context, occurrence EventOccurrence, scope OccurrenceScope, params UpdateCalendarEventOccurrenceParams) (recording *generated.Recording, err error)

UpdateOccurrence updates one day of a repeating event and returns it as a recording.

PATCH /calendar/events/{event id}/occurrences/{YYYY-MM-DD}.json. A date that is not an occurrence of that series is a 404, as is an event the caller cannot edit — the occurrence routes want edit rights on both the day and the series, which is stricter than the whole-event update.

type CalendarList added in v0.21.0

type CalendarList struct {
	Calendars           []ListedCalendar `json:"calendars"`
	CalendarChangesURL  string           `json:"calendar_changes_url"`
	SelectedCalendarIDs []int64          `json:"selected_calendar_ids"`
}

CalendarList is the full calendars index: every calendar with its changes URL and signed stream name, the calendar-level changes feed's own URL, and which calendars the user has selected for display.

type CalendarPeriodsService added in v0.16.0

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

CalendarPeriodsService reads the calendar as the periods it is drawn in: a day, a week, a year. Every read is scoped to the calendars the identity has switched on, which CalendarsService.Toggle changes.

A period is not the same answer as CalendarsService.GetRecordings. A calendar lists the recordings it holds, recurring ones included as the single rows they are stored as; a period expands those into the occurrences that fall inside its window. Draw a week from a calendar's recordings and a weekly meeting shows up once.

func NewCalendarPeriodsService added in v0.16.0

func NewCalendarPeriodsService(client *Client) *CalendarPeriodsService

NewCalendarPeriodsService creates a new CalendarPeriodsService.

func (*CalendarPeriodsService) Day added in v0.16.0

Day returns one day. The date is YYYY-MM-DD, or the literal "now" for today.

func (*CalendarPeriodsService) Days added in v0.16.0

func (s *CalendarPeriodsService) Days(ctx context.Context, startsAt string) (days []generated.CalendarPeriod, err error)

Days returns the days from a date onwards. HEY picks how many — this is a window rather than a page, so the way to read on is to ask again from the last day it answered. An empty date starts from today.

func (*CalendarPeriodsService) Week added in v0.16.0

func (s *CalendarPeriodsService) Week(ctx context.Context, date string) (week *generated.CalendarPeriod, err error)

Week returns the week any date falls in. The date is YYYY-MM-DD.

func (*CalendarPeriodsService) Weeks added in v0.16.0

func (s *CalendarPeriodsService) Weeks(ctx context.Context, startsAt, centeredAt string) (weeks []generated.CalendarPeriod, err error)

Weeks returns nine weeks. `startsAt` names the first of them; `centeredAt` centers them on a date instead, which is what the web app's scrolling week view asks for. Both empty centers on today, and `startsAt` wins if both are given.

func (*CalendarPeriodsService) Year added in v0.16.0

func (s *CalendarPeriodsService) Year(ctx context.Context, date string) (year *generated.CalendarYear, err error)

Year returns the year any date falls in, as the grid it is drawn as: one entry per day and the events that span more than one. A year does not carry every recording it holds.

type CalendarRecordingsPage added in v0.25.0

type CalendarRecordingsPage struct {
	Recordings *generated.CalendarRecordingsResponse
	NextPage   string
}

CalendarRecordingsPage is one page of a calendar's recordings and the cursor for the page after it. NextPage is empty on the last page.

type CalendarTodosService

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

CalendarTodosService handles calendar todo operations.

func NewCalendarTodosService

func NewCalendarTodosService(client *Client) *CalendarTodosService

NewCalendarTodosService creates a new CalendarTodosService.

func (*CalendarTodosService) Complete

func (s *CalendarTodosService) Complete(ctx context.Context, todoID int64) (result *generated.Recording, err error)

Complete marks a calendar todo as complete.

func (*CalendarTodosService) Create

func (s *CalendarTodosService) Create(ctx context.Context, title string, startsAt string) (result *generated.Recording, err error)

Create creates a new calendar todo.

The HEY API expects the body wrapped as {calendar_todo: {title, starts_at}}. If startsAt is empty, it defaults to today.

func (*CalendarTodosService) Delete

func (s *CalendarTodosService) Delete(ctx context.Context, todoID int64) (err error)

Delete deletes a calendar todo.

func (*CalendarTodosService) Uncomplete

func (s *CalendarTodosService) Uncomplete(ctx context.Context, todoID int64) (result *generated.Recording, err error)

Uncomplete marks a calendar todo as incomplete.

func (*CalendarTodosService) Update added in v0.14.0

func (s *CalendarTodosService) Update(ctx context.Context, todoID int64, changes TodoChanges) (result *generated.Recording, err error)

Update edits a calendar todo. todoID is the recording's id.

Changing nothing is refused rather than sent: an empty payload asks the server to do nothing and answers as though it had done something.

type CalendarsService

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

CalendarsService handles calendar operations.

func NewCalendarsService

func NewCalendarsService(client *Client) *CalendarsService

NewCalendarsService creates a new CalendarsService.

func (*CalendarsService) AllCalendarChanges added in v0.21.0

func (s *CalendarsService) AllCalendarChanges(ctx context.Context, cursor CalendarChangesCursor) (*CalendarChanges, error)

AllCalendarChanges reads the calendar changes feed from a cursor to its end.

func (*CalendarsService) AllRecordingChanges added in v0.21.0

func (s *CalendarsService) AllRecordingChanges(ctx context.Context, calendarID int64, cursor CalendarChangesCursor) (*RecordingChanges, error)

AllRecordingChanges reads a calendar's recording changes feed from a cursor to its end.

func (*CalendarsService) CalendarChanges added in v0.21.0

func (s *CalendarsService) CalendarChanges(ctx context.Context, cursor CalendarChangesCursor) (result *CalendarChanges, err error)

CalendarChanges returns one page of the calendar changes feed.

func (*CalendarsService) GetRecordings

GetRecordings returns one requested page of recordings for a specific calendar. GetRecordingsPage also returns the cursor needed to continue through the window.

func (*CalendarsService) GetRecordingsPage added in v0.25.0

func (s *CalendarsService) GetRecordingsPage(ctx context.Context, calendarID int64, params *generated.GetCalendarRecordingsParams) (result *CalendarRecordingsPage, err error)

GetRecordingsPage returns recordings for a specific calendar along with the cursor for the page after them. Leave Page empty for the first page, then set it to each NextPage.

func (*CalendarsService) List

func (s *CalendarsService) List(ctx context.Context) (result *generated.CalendarListPayload, err error)

List returns all calendars.

func (*CalendarsService) ListWithChanges added in v0.21.0

func (s *CalendarsService) ListWithChanges(ctx context.Context) (result *CalendarList, err error)

ListWithChanges returns all calendars along with everything List throws away: each calendar's recording changes URL and signed stream name, the calendar changes URL, and the selected calendar IDs.

func (*CalendarsService) RecordingChanges added in v0.21.0

func (s *CalendarsService) RecordingChanges(ctx context.Context, calendarID int64, cursor CalendarChangesCursor) (result *RecordingChanges, err error)

RecordingChanges returns one page of a calendar's recording changes feed.

func (*CalendarsService) Toggle added in v0.16.0

func (s *CalendarsService) Toggle(ctx context.Context, calendarID int64) (selectedIDs []int64, err error)

Toggle switches a calendar in or out of the identity's selection and returns the ids the selection is left holding. The selection is what CalendarPeriodsService reads are scoped to, so this is how a client changes which calendars a day, week or year is drawn from.

type ChainHooks

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

ChainHooks combines multiple Hooks implementations.

func (*ChainHooks) OnOperationEnd

func (c *ChainHooks) OnOperationEnd(ctx context.Context, op OperationInfo, err error, duration time.Duration)

func (*ChainHooks) OnOperationGate

func (c *ChainHooks) OnOperationGate(ctx context.Context, op OperationInfo) (context.Context, error)

func (*ChainHooks) OnOperationStart

func (c *ChainHooks) OnOperationStart(ctx context.Context, op OperationInfo) context.Context

func (*ChainHooks) OnRequestEnd

func (c *ChainHooks) OnRequestEnd(ctx context.Context, info RequestInfo, result RequestResult)

func (*ChainHooks) OnRequestStart

func (c *ChainHooks) OnRequestStart(ctx context.Context, info RequestInfo) context.Context

func (*ChainHooks) OnRetry

func (c *ChainHooks) OnRetry(ctx context.Context, info RequestInfo, attempt int, err error)

type CircuitBreakerConfig

type CircuitBreakerConfig struct {
	FailureThreshold     int
	SuccessThreshold     int
	OpenTimeout          time.Duration
	FailureRateThreshold float64
	SlidingWindowSize    int
	Now                  func() time.Time
}

CircuitBreakerConfig configures the circuit breaker.

func DefaultCircuitBreakerConfig

func DefaultCircuitBreakerConfig() *CircuitBreakerConfig

DefaultCircuitBreakerConfig returns production-ready defaults.

type ClearancePage added in v0.10.0

type ClearancePage struct {
	Clearances   []generated.Clearance
	PendingCount int
	NextPage     string
}

ClearancePage contains one page of clearances and the cursor for the page after it. PendingCount is what the Screener holds in total and is only answered by PendingPage.

type ClearancesService added in v0.7.0

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

ClearancesService works the Screener: who is waiting to be let in, and letting them in or turning them away.

func NewClearancesService added in v0.7.0

func NewClearancesService(client *Client) *ClearancesService

NewClearancesService creates a new ClearancesService.

func (*ClearancesService) Pending added in v0.7.0

func (s *ClearancesService) Pending(ctx context.Context, page string) (summary *generated.ClearanceSummary, err error)

Pending answers the senders waiting to be screened, a page at a time.

Each one carries the petitioner and the most recent entry they sent, so a caller can show who is asking and what they wrote without a second read. Pass the page token from a previous answer to walk the queue.

func (*ClearancesService) PendingCount added in v0.7.0

func (s *ClearancesService) PendingCount(ctx context.Context) (count int, err error)

PendingCount answers how many senders are waiting, without fetching them.

This is the cheap read HEY's own apps sync for the Screener badge. Use Pending when you want the senders themselves, or Summary when you also want the stream to follow.

func (*ClearancesService) PendingPage added in v0.10.0

func (s *ClearancesService) PendingPage(ctx context.Context, page string) (result *ClearancePage, err error)

PendingPage answers the same queue as Pending along with the cursor for the page after it, so a caller walking the queue is told when it has reached the end of it.

func (*ClearancesService) Punt added in v0.7.0

func (s *ClearancesService) Punt(ctx context.Context) error

Punt clears the Screener. Everyone waiting is dropped and reexamined the next time they write, so nothing is decided for them.

The work is queued, so the senders are still pending when this returns.

func (*ClearancesService) Rescreen added in v0.7.0

func (s *ClearancesService) Rescreen(ctx context.Context, clearanceID int64, status string) (clearance *generated.Clearance, err error)

Rescreen changes its mind about a sender already screened in or out.

This is the decided list, not the queue: Screen is what answers a pending sender.

func (*ClearancesService) Screen added in v0.7.0

func (s *ClearancesService) Screen(ctx context.Context, clearanceID int64, status string, opts ScreenOptions) (clearance *generated.Clearance, err error)

Screen answers the Screener for one sender. Status is ClearanceApproved or ClearanceDenied.

The options are all optional: file everything they send into a box instead of the Imbox, mark what is already waiting as spam, or mark it seen so it does not arrive unread.

func (*ClearancesService) ScreenMany added in v0.7.0

func (s *ClearancesService) ScreenMany(ctx context.Context, clearanceIDs []int64, status string, spam bool) (clearances []generated.Clearance, err error)

ScreenMany screens several senders at once and answers the clearances it changed.

HEY answers 404 when none of the ids belong to the caller. A partial match succeeds and answers only what it touched, so compare the answer against what you sent.

func (*ClearancesService) Screened added in v0.7.0

func (s *ClearancesService) Screened(ctx context.Context, page string) (clearances []generated.Clearance, err error)

Screened answers the senders already screened in or out, newest decision first, a page at a time.

func (*ClearancesService) ScreenedPage added in v0.10.0

func (s *ClearancesService) ScreenedPage(ctx context.Context, page string) (result *ClearancePage, err error)

ScreenedPage answers the same decisions as Screened along with the cursor for the page after it.

func (*ClearancesService) Summary added in v0.8.0

func (s *ClearancesService) Summary(ctx context.Context) (summary *generated.ClearanceSummary, err error)

Summary answers everything HEY says about the Screener without the queue itself: how many senders are waiting, and the signed stream name to subscribe to on HEY's cable server to be told when that changes.

It is the same read as PendingCount — the count alone, no queue dragged along.

type Client

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

Client is an HTTP client for the HEY API. A root client represents the authenticated identity and presents mail from All Accounts. ForAccount derives an immutable client that presents mail for one linked account.

Client is safe for concurrent use after construction.

func NewClient

func NewClient(cfg *Config, tokenProvider TokenProvider, opts ...ClientOption) *Client

NewClient creates a new API client.

func (*Client) AccountID added in v0.6.0

func (c *Client) AccountID() (accountID int64, ok bool)

AccountID returns the linked account selected for this client. The boolean is false for an All Accounts client.

func (*Client) AccountUserID added in v0.6.0

func (c *Client) AccountUserID(ctx context.Context) (int64, error)

AccountUserID returns the authenticated identity's user ID in the selected linked account.

func (*Client) Attachments added in v0.5.0

func (c *Client) Attachments() *AttachmentsService

Attachments returns the attachment service.

func (*Client) BoxIDByKind added in v0.4.0

func (c *Client) BoxIDByKind(ctx context.Context, kind string) (int64, error)

BoxIDByKind returns the ID of the caller's box with the given kind ("imbox", "feedbox", "asidebox", "laterbox", "trailbox", "bubblebox"), resolving via ListBoxes on first use and caching the result.

func (*Client) Boxes

func (c *Client) Boxes() *BoxesService

Boxes returns the BoxesService.

func (*Client) BulkReplies added in v0.4.0

func (c *Client) BulkReplies() *BulkRepliesService

BulkReplies returns the bulk reply service, for answering many threads at once.

func (*Client) CalendarEvents added in v0.4.0

func (c *Client) CalendarEvents() *CalendarEventsService

CalendarEvents returns the CalendarEventsService.

func (*Client) CalendarPeriods added in v0.16.0

func (c *Client) CalendarPeriods() *CalendarPeriodsService

CalendarPeriods returns the CalendarPeriodsService.

func (*Client) CalendarTodos

func (c *Client) CalendarTodos() *CalendarTodosService

CalendarTodos returns the CalendarTodosService.

func (*Client) Calendars

func (c *Client) Calendars() *CalendarsService

Calendars returns the CalendarsService.

func (*Client) Clearances added in v0.7.0

func (c *Client) Clearances() *ClearancesService

Clearances returns the ClearancesService, for working the Screener.

func (*Client) Clips added in v0.4.0

func (c *Client) Clips() *ClipsService

Clips returns the ClipsService.

func (*Client) Collections added in v0.4.0

func (c *Client) Collections() *CollectionsService

Collections returns the CollectionsService.

func (*Client) Config

func (c *Client) Config() Config

Config returns a copy of the client configuration.

func (*Client) Contacts

func (c *Client) Contacts() *ContactsService

Contacts returns the ContactsService.

func (*Client) DefaultSenderID added in v0.1.1

func (c *Client) DefaultSenderID(ctx context.Context) (int64, error)

DefaultSenderID returns the default sender contact ID for this client. An account-scoped client selects only senders belonging to its account. An All Accounts client preserves the identity-wide default sender behavior.

The result is cached after the first successful call. Transient errors are not cached, so subsequent calls retry the identity fetch.

func (*Client) Delete

func (c *Client) Delete(ctx context.Context, path string) (*Response, error)

Delete performs a DELETE request.

func (*Client) DeleteForm added in v0.4.0

func (c *Client) DeleteForm(ctx context.Context, path string) (*FormResponse, error)

DeleteForm performs a DELETE request that expects a redirect response.

func (*Client) Designations added in v0.4.0

func (c *Client) Designations() *DesignationsService

Designations returns the DesignationsService.

func (*Client) DownloadBlob added in v0.5.0

func (c *Client) DownloadBlob(ctx context.Context, path string, destination io.Writer) (int64, http.Header, error)

DownloadBlob streams a blob to destination without placing the complete file in memory. It returns the number of bytes written and the final response headers.

func (*Client) Entries

func (c *Client) Entries() *EntriesService

Entries returns the EntriesService.

func (*Client) Extenzions added in v0.4.0

func (c *Client) Extenzions() *ExtenzionsService

Extenzions returns the ExtenzionsService.

func (*Client) Folders added in v0.4.0

func (c *Client) Folders() *FoldersService

Folders returns the FoldersService.

func (*Client) FollowPagination

func (c *Client) FollowPagination(ctx context.Context, httpResp *http.Response, firstPageCount, limit int) ([]json.RawMessage, error)

FollowPagination fetches additional pages following Link headers from an HTTP response. firstPageCount is the number of items already collected from the first page. limit is the maximum total items to return (0 = unlimited). Returns raw JSON items from subsequent pages only.

func (*Client) ForAccount added in v0.6.0

func (c *Client) ForAccount(ctx context.Context, accountID int64) (*Client, error)

ForAccount returns an immutable client that presents HEY's mail data for one accessible linked account. It verifies the account against the authenticated identity before returning. The returned client shares transport, authentication, hooks, logging, configuration, and HTTP cache with its source while maintaining its own generated client, services, and account-sensitive caches.

HEY applies account scope to mail-oriented operations. Identity-owned operations, including Calendar and Journal, retain their identity-wide semantics. Account scope is a presentation and acting-account context, not an authorization boundary.

func (*Client) Get

func (c *Client) Get(ctx context.Context, path string) (*Response, error)

Get performs a GET request.

func (*Client) GetAll

func (c *Client) GetAll(ctx context.Context, path string) ([]json.RawMessage, error)

GetAll fetches all pages for a paginated resource.

func (*Client) GetAllWithLimit

func (c *Client) GetAllWithLimit(ctx context.Context, path string, limit int) ([]json.RawMessage, error)

GetAllWithLimit fetches pages for a paginated resource up to a limit.

func (*Client) GetBlob added in v0.5.0

func (c *Client) GetBlob(ctx context.Context, path string) (*Response, error)

GetBlob performs a same-origin GET request for binary content and bypasses the response cache. It buffers up to MaxResponseBodyBytes; DownloadBlob streams files of any size. Redirects may leave the HEY origin, and the HTTP client strips authorization before following them.

func (*Client) GetCSV added in v0.4.0

func (c *Client) GetCSV(ctx context.Context, path string) (*Response, error)

GetCSV performs a GET request with Accept: text/csv, returning the raw CSV bytes. Use this for the export endpoints, which stream a file rather than a document.

func (*Client) GetHTML added in v0.3.0

func (c *Client) GetHTML(ctx context.Context, path string) (*Response, error)

GetHTML performs a GET request with Accept: text/html, returning raw HTML bytes. Use this for endpoints that only serve HTML (no JSON equivalent).

func (*Client) Habits

func (c *Client) Habits() *HabitsService

Habits returns the HabitsService.

func (*Client) Identity

func (c *Client) Identity() *IdentityService

Identity returns the IdentityService.

func (*Client) Journal

func (c *Client) Journal() *JournalService

Journal returns the JournalService.

func (*Client) Messages

func (c *Client) Messages() *MessagesService

Messages returns the MessagesService.

func (*Client) Patch

func (c *Client) Patch(ctx context.Context, path string, body any) (*Response, error)

Patch performs a PATCH request with a JSON body.

func (*Client) PatchForm added in v0.4.0

func (c *Client) PatchForm(ctx context.Context, path string, values url.Values) (*FormResponse, error)

PatchForm performs a PATCH request with a form-encoded body. The server is expected to respond with a redirect (302/303).

func (*Client) PatchMutation added in v0.1.1

func (c *Client) PatchMutation(ctx context.Context, path string, body any) (*Response, error)

PatchMutation performs a PATCH mutation with Accept: */*. Use this for endpoints where the server may not return JSON.

func (*Client) Post

func (c *Client) Post(ctx context.Context, path string, body any) (*Response, error)

Post performs a POST request with a JSON body.

func (*Client) PostForm added in v0.4.0

func (c *Client) PostForm(ctx context.Context, path string, values url.Values) (*FormResponse, error)

PostForm performs a POST request with a form-encoded body. The server is expected to respond with a redirect (302/303); the redirect is captured rather than followed, and the Location header is returned.

func (*Client) PostMultipart added in v0.4.0

func (c *Client) PostMultipart(ctx context.Context, path, contentType string, body []byte) (*FormResponse, error)

PostMultipart performs a POST request with a multipart body, for the endpoints that take a file upload. The server is expected to respond with a redirect (302/303).

func (*Client) PostMutation added in v0.1.1

func (c *Client) PostMutation(ctx context.Context, path string, body any) (*Response, error)

PostMutation performs a POST mutation with Accept: */*. Use this for endpoints where the server may not return JSON.

func (*Client) Postings added in v0.2.0

func (c *Client) Postings() *PostingsService

Postings returns the PostingsService.

func (*Client) Publications added in v0.4.0

func (c *Client) Publications() *PublicationsService

Publications returns the PublicationsService.

func (*Client) Put

func (c *Client) Put(ctx context.Context, path string, body any) (*Response, error)

Put performs a PUT request with a JSON body.

func (*Client) Search

func (c *Client) Search() *SearchService

Search returns the SearchService.

func (*Client) Snippets added in v0.4.0

func (c *Client) Snippets() *SnippetsService

Snippets returns the SnippetsService.

func (*Client) Stickies added in v0.4.0

func (c *Client) Stickies() *StickiesService

Stickies returns the StickiesService.

func (*Client) TimeTracks

func (c *Client) TimeTracks() *TimeTracksService

TimeTracks returns the TimeTracksService.

func (*Client) Topics

func (c *Client) Topics() *TopicsService

Topics returns the TopicsService.

func (*Client) Workflows added in v0.4.0

func (c *Client) Workflows() *WorkflowsService

Workflows returns the WorkflowsService.

func (*Client) World added in v0.4.0

func (c *Client) World() *WorldService

World returns the WorldService.

type ClientOption

type ClientOption func(*Client)

ClientOption configures a Client.

func WithAuthStrategy

func WithAuthStrategy(strategy AuthStrategy) ClientOption

WithAuthStrategy sets a custom authentication strategy.

func WithBaseDelay

func WithBaseDelay(d time.Duration) ClientOption

WithBaseDelay sets the initial backoff delay.

func WithBulkhead

func WithBulkhead(cfg *BulkheadConfig) ClientOption

WithBulkhead enables only the bulkhead (concurrency limiter).

func WithCache

func WithCache(cache *Cache) ClientOption

WithCache sets a custom cache.

func WithCircuitBreaker

func WithCircuitBreaker(cfg *CircuitBreakerConfig) ClientOption

WithCircuitBreaker enables only the circuit breaker.

func WithHTTPClient

func WithHTTPClient(c *http.Client) ClientOption

WithHTTPClient sets a custom HTTP client. It replaces the one NewClient would build, so none of what that one carries — the request timeout, credential stripping on cross-origin redirects, the response body cap, logging and hooks — applies to it. WithTransport keeps all of that and swaps only the transport underneath.

func WithHooks

func WithHooks(hooks Hooks) ClientOption

WithHooks sets the observability hooks for the client.

func WithLogger

func WithLogger(l *slog.Logger) ClientOption

WithLogger sets a custom slog logger for debug output.

func WithMaxJitter

func WithMaxJitter(d time.Duration) ClientOption

WithMaxJitter sets the maximum random jitter to add to delays.

func WithMaxPages

func WithMaxPages(n int) ClientOption

WithMaxPages sets the maximum pages to fetch in GetAll.

func WithMaxResponseBodyBytes added in v0.13.0

func WithMaxResponseBodyBytes(n int64) ClientOption

WithMaxResponseBodyBytes sets the most a JSON or HTML response body may deliver, in decompressed bytes, before its read fails with an error wrapping ErrResponseTooLarge. 0 or a negative value restores DefaultMaxResponseBodyBytes; the cap cannot be removed.

func WithMaxRetries

func WithMaxRetries(n int) ClientOption

WithMaxRetries sets the maximum number of retry attempts for GET requests.

func WithRateLimit

func WithRateLimit(cfg *RateLimitConfig) ClientOption

WithRateLimit enables only client-side rate limiting.

func WithResilience

func WithResilience(cfg *ResilienceConfig) ClientOption

WithResilience enables circuit breaker, bulkhead, and rate limiting.

func WithTimeout

func WithTimeout(d time.Duration) ClientOption

WithTimeout sets the HTTP request timeout.

func WithTransport

func WithTransport(t http.RoundTripper) ClientOption

WithTransport sets a custom HTTP transport. The SDK still wraps it with its own response body cap, logging and hooks; WithHTTPClient is the option that replaces all of that.

func WithUserAgent

func WithUserAgent(ua string) ClientOption

WithUserAgent sets the User-Agent header.

type ClipsService added in v0.4.0

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

ClipsService handles clips — snippets of a message you saved for later.

Clips have no JSON surface: writes answer with a Turbo Stream and the list is HTML, so the list is read off the page.

func NewClipsService added in v0.4.0

func NewClipsService(client *Client) *ClipsService

NewClipsService creates a new ClipsService.

func (*ClipsService) Create added in v0.4.0

func (s *ClipsService) Create(ctx context.Context, entryID int64, content string) error

func (*ClipsService) Delete added in v0.4.0

func (s *ClipsService) Delete(ctx context.Context, clipID int64) error

Delete throws a clip away.

func (*ClipsService) List added in v0.4.0

func (s *ClipsService) List(ctx context.Context) (result []generated.Clip, err error)

List returns the clips, newest first, as HEY renders them (content, the entry they were taken from, and the topic).

type CollectionPage added in v0.8.0

type CollectionPage struct {
	Collection *generated.CollectionWithPostings
	NextPage   string
	TotalCount int
}

CollectionPage contains one page of a collection and its pagination state.

type CollectionsService added in v0.4.0

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

CollectionsService handles collections — shared threads gathered under one name.

func NewCollectionsService added in v0.4.0

func NewCollectionsService(client *Client) *CollectionsService

NewCollectionsService creates a new CollectionsService.

func (*CollectionsService) AddTopic added in v0.4.0

func (s *CollectionsService) AddTopic(ctx context.Context, topicID int64, collectionID int64) error

AddTopic files a topic into a collection.

HEY has no JSON endpoint for this — the form post answers with a redirect to the topic.

func (*CollectionsService) Create added in v0.4.0

Create makes a new collection.

HEY has no JSON endpoint for this — the form post answers with a redirect to the collections index rather than the new collection, so the id is not returned. List afterwards to find it.

func (*CollectionsService) Get added in v0.8.0

Get returns a collection and the active, accessible threads in its requested page.

func (*CollectionsService) GetPage added in v0.8.0

func (s *CollectionsService) GetPage(ctx context.Context, collectionID int64, params *generated.GetCollectionParams) (result *CollectionPage, err error)

GetPage returns a collection page with its next cursor and total posting count.

func (*CollectionsService) List added in v0.4.0

List returns your collections.

func (*CollectionsService) RemoveTopic added in v0.4.0

func (s *CollectionsService) RemoveTopic(ctx context.Context, topicID int64, collectionID int64) error

RemoveTopic takes a topic back out of a collection.

HEY has no JSON endpoint for this — the form post answers with a redirect to the topic. Shadowed topics are silently left alone.

func (*CollectionsService) Update added in v0.4.0

func (s *CollectionsService) Update(ctx context.Context, collectionID int64, params UpdateCollectionParams) error

Update renames a collection or changes its summary.

type Config

type Config struct {
	// BaseURL is the API base URL (e.g., "https://app.hey.com").
	BaseURL string `json:"base_url"`

	// OAuthClientID is the OAuth 2.0 client ID for HEY.
	OAuthClientID string `json:"oauth_client_id"`

	// CacheDir is the directory for HTTP cache storage.
	CacheDir string `json:"cache_dir"`

	// CacheEnabled controls whether HTTP caching is enabled.
	CacheEnabled bool `json:"cache_enabled"`
}

Config holds the resolved configuration for API access.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a Config with sensible defaults.

func LoadConfig

func LoadConfig(path string) (*Config, error)

LoadConfig loads configuration from a JSON file.

func (*Config) LoadConfigFromEnv

func (c *Config) LoadConfigFromEnv()

LoadConfigFromEnv loads configuration from environment variables. Environment variables override any values already set in the config.

type ContactConflictError added in v0.4.0

type ContactConflictError struct {
	ContactID             int64
	ConflictingContactIDs []int64
	// contains filtered or unexported fields
}

ContactConflictError is returned when a contact write submits an email address that already belongs to another contact. HEY's web sends you to a merge form at that point; ConflictingContactIDs are the contacts it would have offered to merge with.

A create that clashes still creates the contact — the merge happens afterwards — so ContactID is the contact that was written, not a contact that failed to be.

It wraps the SDK's conflict error, so errors.As still finds a *hey.Error with CodeConflict for callers that only care that the write was refused.

func (*ContactConflictError) Error added in v0.4.0

func (e *ContactConflictError) Error() string

Error implements the error interface.

func (*ContactConflictError) Unwrap added in v0.4.0

func (e *ContactConflictError) Unwrap() error

Unwrap returns the underlying conflict error.

type ContactPage added in v0.27.0

type ContactPage struct {
	Contact  *generated.ContactDetail
	NextPage string
}

ContactPage is one page of a contact and the threads they are on: the cursor for the page below is empty on the last page.

type ContactParams added in v0.4.0

type ContactParams struct {
	// Name is the contact's display name.
	Name string
	// EmailAddress is their main address.
	EmailAddress string
	// AliasEmailAddresses are other addresses that belong to the same person.
	AliasEmailAddresses []string
	// AccountUserID picks the account the contact belongs to, on Create. One identity can
	// hold several accounts, each with its own contacts; this is the identity's user on
	// the one you mean, which Identity returns in all_users alongside its account_id.
	// Left zero, HEY files the contact under the first account. Update ignores it.
	AccountUserID int64
}

ContactParams describes a contact.

type ContactsService

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

ContactsService handles contact operations.

func NewContactsService

func NewContactsService(client *Client) *ContactsService

NewContactsService creates a new ContactsService.

func (*ContactsService) Bundle added in v0.4.0

func (s *ContactsService) Bundle(ctx context.Context, contactID int64) error

Bundle groups a contact's mail together in the box instead of listing every thread.

func (*ContactsService) Clearances deprecated added in v0.4.0

func (s *ContactsService) Clearances(ctx context.Context) (result *generated.ClearanceSummary, err error)

Clearances returns the screener summary — how many senders are waiting to be screened.

Deprecated: use Client.Clearances(). PendingCount answers the same count, and Pending answers the senders themselves.

func (*ContactsService) Create added in v0.4.0

func (s *ContactsService) Create(ctx context.Context, params ContactParams) (contact *generated.Contact, err error)

Create adds a contact and returns it.

func (*ContactsService) DeleteNote added in v0.4.0

func (s *ContactsService) DeleteNote(ctx context.Context, contactID int64) error

DeleteNote clears the private note on a contact.

func (*ContactsService) Get

func (s *ContactsService) Get(ctx context.Context, contactID int64) (result *generated.ContactDetail, err error)

Get returns a specific contact by ID.

func (*ContactsService) Hide added in v0.4.0

func (s *ContactsService) Hide(ctx context.Context, contactID int64) error

Hide takes a contact out of the contact list. Nothing is deleted — Reveal brings them back.

func (*ContactsService) List

List returns all contacts.

func (*ContactsService) Note added in v0.4.0

func (s *ContactsService) Note(ctx context.Context, contactID int64) (note *generated.ContactNote, err error)

Note returns the private note kept on a contact. Its fields are empty strings when there is no note.

func (*ContactsService) Reveal added in v0.4.0

func (s *ContactsService) Reveal(ctx context.Context, contactID int64) (contact *generated.Contact, err error)

Reveal puts a hidden contact back in the contact list and returns it.

func (*ContactsService) Screen added in v0.4.0

func (s *ContactsService) Screen(ctx context.Context, contactID int64, status string) error

Screen answers the screener for a contact. Status is ClearanceApproved or ClearanceDenied.

func (*ContactsService) SetNote added in v0.4.0

func (s *ContactsService) SetNote(ctx context.Context, contactID int64, note string) (result *generated.ContactNote, err error)

SetNote writes the private note you keep on a contact, replacing whatever was there, and returns the note as it now reads.

func (*ContactsService) ThreadsPage added in v0.27.0

func (s *ContactsService) ThreadsPage(ctx context.Context, contactID int64, cursor string) (result *ContactPage, err error)

ThreadsPage reads a contact with one page of the threads they are on — what HEY heads "All threads with …" (the contact's entries_title). An empty cursor starts at the top; the next page's cursor comes back on the page before it.

func (*ContactsService) Unbundle added in v0.4.0

func (s *ContactsService) Unbundle(ctx context.Context, contactID int64) error

Unbundle stops grouping a contact's mail.

func (*ContactsService) Update added in v0.4.0

func (s *ContactsService) Update(ctx context.Context, contactID int64, params ContactParams) (contact *generated.Contact, err error)

Update edits a contact and returns it. Empty fields are left alone, except AliasEmailAddresses, which replaces the whole list when it is non-nil.

HEY's update is a full replacement (Contact::Ingress::Revise rewrites name, email and removes any alias not submitted), so the current contact is read first and unset fields are filled in from it before the write. That read-then-write is not atomic: a change made to the contact in between is overwritten with what was read. Pass every field explicitly when that matters.

The contact that comes back is not always the one addressed: promoting an alias to the main address makes the alias the primary contact, and that is the one returned.

type CountdownParams added in v0.19.0

type CountdownParams struct {
	Value int
	Unit  CountdownUnit
}

CountdownParams is the countdown HEY runs up to an event, and like EventContentParams it is resend-or-lose-it: HEY reads the pair on every editable write and a missing value deletes the countdown. The zero value therefore means the event has no countdown once the write lands.

A countdown is a child recording of its own rather than a field on the event, so it is not on the event's JSON and cannot be read back from one. Value 1–30 is what the web app offers.

type CountdownUnit added in v0.19.0

type CountdownUnit int

CountdownUnit is one countdown unit as a number of seconds, which is the form HEY's own form submits and the only one it reads.

const (
	CountdownUnitDays   CountdownUnit = 86400
	CountdownUnitWeeks  CountdownUnit = 604800
	CountdownUnitMonths CountdownUnit = 2629746
)

type CreateCalendarEventParams added in v0.4.0

type CreateCalendarEventParams struct {
	// CalendarID is the ID of the calendar to create the event in.
	CalendarID int64
	// Title is the event summary/title.
	Title string
	// StartsAt is the start date in YYYY-MM-DD format.
	StartsAt string
	// EndsAt is the end date in YYYY-MM-DD format. Defaults to StartsAt if empty.
	EndsAt string
	// AllDay indicates whether this is an all-day event.
	AllDay bool
	// StartTime is the start time in HH:MM format (required if not all-day).
	StartTime string
	// EndTime is the end time in HH:MM format (required if not all-day).
	EndTime string
	// StartTimeZone and EndTimeZone are the IANA names of the zones the clock times above are
	// written in — "Europe/Zagreb", "America/New_York". Leave them empty and the times are
	// read in UTC, which is the zone HEY parses an API request in. HEY keeps a zone per end,
	// as its own form offers, so an event can start in one and finish in another.
	StartTimeZone string
	EndTimeZone   string
	// TimeZone names one zone for both ends.
	//
	// Deprecated: use StartTimeZone and EndTimeZone. It stands in for whichever of them is
	// empty, so a caller that only ever wanted one zone keeps working.
	TimeZone string
	// Reminders is a list of durations before the event to send reminders. HEY takes several in
	// one write and de-duplicates them, and accepts any duration rather than only the presets
	// the web app offers. Only the list matching the event's all-day flag is read.
	//
	// Empty means no reminders. On an update that is not "leave them alone" but "remove them",
	// so a partial update that forgets them silently unschedules every one.
	Reminders []time.Duration
	// Content is the notes, location, link and attached entry. Nothing exists to lose on a
	// create, so the zero value is simply an event with none of them.
	Content EventContentParams
	// Attendees is the guest list. Submitting one makes the caller the organizer and sends
	// invitations.
	Attendees []string
	// Highlighted circles the event. HEY reads it only when it is submitted, so nil is "not
	// circled" on a create.
	Highlighted *bool
	// Countdown counts down to the event. The zero value creates none.
	Countdown CountdownParams
	// Repeat makes the event recurring. A nil one is a one-off.
	Repeat *RepeatParams
}

CreateCalendarEventParams contains the parameters for creating a calendar event.

type CreateCollectionParams added in v0.4.0

type CreateCollectionParams struct {
	// Name is what the collection is called.
	Name string
	// Summary is the optional blurb shown under the name.
	Summary string
	// AccountID picks which account owns it. Zero leaves the server to pick your first.
	AccountID int64
}

CreateCollectionParams contains the parameters for creating a collection.

type CreateExtenzionParams added in v0.4.0

type CreateExtenzionParams struct {
	// Name is the extenzion name (e.g., "sales" becomes sales@yourdomain.com).
	Name string
	// Members is a list of member email addresses.
	Members []string
}

CreateExtenzionParams contains the parameters for creating an extenzion.

type CredentialStore

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

CredentialStore handles secure credential storage.

func NewCredentialStore

func NewCredentialStore(fallbackDir string) *CredentialStore

NewCredentialStore creates a credential store.

func (*CredentialStore) Delete

func (s *CredentialStore) Delete(origin string) error

Delete removes credentials for the given origin.

func (*CredentialStore) Load

func (s *CredentialStore) Load(origin string) (*Credentials, error)

Load retrieves credentials for the given origin.

func (*CredentialStore) Save

func (s *CredentialStore) Save(origin string, creds *Credentials) error

Save stores credentials for the given origin.

func (*CredentialStore) UsingKeyring

func (s *CredentialStore) UsingKeyring() bool

UsingKeyring returns true if the store is using the system keyring.

type Credentials

type Credentials struct {
	AccessToken   string `json:"access_token"`
	RefreshToken  string `json:"refresh_token"`
	ExpiresAt     int64  `json:"expires_at"`
	Scope         string `json:"scope"`
	TokenEndpoint string `json:"token_endpoint"`
	UserID        string `json:"user_id,omitempty"`
}

Credentials holds OAuth tokens and metadata.

type DeletedCalendar added in v0.21.0

type DeletedCalendar struct {
	ID        int64     `json:"id"`
	DeletedAt time.Time `json:"deleted_at"`
}

DeletedCalendar is a calendar the changes feed reports gone.

type DeletedRecording added in v0.21.0

type DeletedRecording struct {
	ID        int64     `json:"id"`
	DeletedAt time.Time `json:"deleted_at"`
	Type      string    `json:"type"`
}

DeletedRecording is a recording the changes feed reports gone. Type is the recordable type key the recording was grouped under while it existed.

type DesignationsService added in v0.4.0

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

DesignationsService screens a contact into a box, so everything they send lands there.

func NewDesignationsService added in v0.4.0

func NewDesignationsService(client *Client) *DesignationsService

NewDesignationsService creates a new DesignationsService.

func (*DesignationsService) Create added in v0.4.0

func (s *DesignationsService) Create(ctx context.Context, boxID int64, contactID int64) error

Create designates a contact to a box.

The server designates the contact's primary, so alias contacts fold into one designation whose id you cannot derive from contactID — read the box back if you need it.

func (*DesignationsService) Destroy added in v0.4.0

func (s *DesignationsService) Destroy(ctx context.Context, boxID int64, designationID int64) error

Destroy removes a designation from a box. designationID is the designation's own id, not the contact's.

type DraftContent added in v0.22.0

type DraftContent struct {
	Subject string
	Content string
	To      []string
	CC      []string
	BCC     []string

	// Schedule delivers the draft at an hour of a day. Nil means no scheduled
	// delivery — and on an update, clears one already set.
	Schedule *DraftSchedule
}

DraftContent is the whole of what a draft carries: the subject, the Trix HTML body, the recipients per kind and any scheduled delivery. HEY revises a draft from the whole of it — see UpdateDraft — so a caller edits by reading the draft (GetEdit), changing fields and sending everything back.

type DraftPage added in v0.22.0

type DraftPage struct {
	Drafts   []generated.DraftMessage
	NextPage string
}

DraftPage is one page of drafts along with the cursor for the page after it. The index pages by geared_pagination's opaque cursor out of the Link header — a page number is answered with the first page forever — so NextPage is the only way to walk it; empty means the last page.

type DraftSchedule added in v0.22.0

type DraftSchedule struct {
	// Date is YYYY-MM-DD, "today" or "tomorrow".
	Date string
	// Hour is 0 through 23.
	Hour int
}

DraftSchedule names a delivery time to the hour, read in the identity's time zone. HEY schedules to the hour; there are no minutes.

type EntriesService

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

EntriesService handles draft and reply operations.

func NewEntriesService

func NewEntriesService(client *Client) *EntriesService

NewEntriesService creates a new EntriesService.

func (*EntriesService) CreateReply

func (s *EntriesService) CreateReply(ctx context.Context, entryID int64, content string, to, cc, bcc []string) (err error)

CreateReply replies to an entry (POST /entries/{entryId}/replies.json) and delivers it. The acting sender ID is automatically resolved.

Recipients are required. HEY does not reply-all on the caller's behalf: a reply posted without entry.addressed is saved as a draft (the server answers with a redirect to the thread with the draft expanded) rather than delivered. Callers resolve the thread's recipients first — hey-cli reads them from the topic page.

func (*EntriesService) CreateReplyDraft added in v0.22.0

func (s *EntriesService) CreateReplyDraft(ctx context.Context, entryID int64, content string, to, cc, bcc []string) (draftEntryID int64, err error)

CreateReplyDraft saves a reply to an entry as a draft instead of delivering it, and answers the draft's entry id. Unlike CreateReply it needs no recipients — HEY keeps whatever the draft carries — and unlike a message draft it carries no subject, since a reply stays under its thread's.

func (*EntriesService) DeleteDraft added in v0.22.0

func (s *EntriesService) DeleteDraft(ctx context.Context, entryID int64) error

DeleteDraft trashes a draft by its entry id, as ListDrafts reports it.

func (*EntriesService) ListDrafts

ListDrafts returns all draft messages.

func (*EntriesService) ListDraftsPage added in v0.22.0

func (s *EntriesService) ListDraftsPage(ctx context.Context, page string) (result *DraftPage, err error)

ListDraftsPage answers the same drafts as ListDrafts along with the cursor for the page after them.

func (*EntriesService) MarkSpam added in v0.4.0

func (s *EntriesService) MarkSpam(ctx context.Context, entryID int64) error

MarkSpam marks an entry as spam. The server denies the sender outright when every thread from them is already spam.

func (*EntriesService) NewForward added in v0.4.0

func (s *EntriesService) NewForward(ctx context.Context, entryID int64) (result *generated.MessageDraft, err error)

NewForward returns a prefilled forward of an entry: the "Fwd:" subject, the quoted body and blank recipients. Fill in the recipients and send it with MessagesService.Create.

func (*EntriesService) NewReply added in v0.22.0

func (s *EntriesService) NewReply(ctx context.Context, entryID int64) (result *generated.MessageDraft, err error)

NewReply returns a prefilled reply to an entry: the quoted body and, in Addressed, the recipients a reply goes to as HEY computes them — the entry's sender moved onto the To line and the acting user's own addresses, aliases and catch-alls excluded. This is the recipient list CreateReply should be handed.

type Error

type Error struct {
	Code       string
	Message    string
	Hint       string
	HTTPStatus int
	Retryable  bool
	RequestID  string
	Cause      error
}

Error is a structured error with code, message, and optional hint.

func AsError

func AsError(err error) *Error

AsError attempts to convert an error to an *Error. If the error is not an *Error, it wraps it in one.

func ErrAPI

func ErrAPI(status int, msg string) *Error

ErrAPI creates an API error with an HTTP status code.

func ErrAmbiguous

func ErrAmbiguous(resource string, matches []string) *Error

ErrAmbiguous creates an ambiguous match error.

func ErrAuth

func ErrAuth(msg string) *Error

ErrAuth creates an authentication error.

func ErrConflict added in v0.4.0

func ErrConflict(msg string) *Error

ErrConflict signals that the request conflicts with current server state (HTTP 409), carrying the server's own message.

func ErrForbidden

func ErrForbidden(msg string) *Error

ErrForbidden creates a forbidden error.

func ErrForbiddenScope

func ErrForbiddenScope() *Error

ErrForbiddenScope creates a forbidden error due to insufficient scope.

func ErrNetwork

func ErrNetwork(cause error) *Error

ErrNetwork creates a network error.

func ErrNotFound

func ErrNotFound(resource, identifier string) *Error

ErrNotFound creates a not-found error.

func ErrNotFoundHint

func ErrNotFoundHint(resource, identifier, hint string) *Error

ErrNotFoundHint creates a not-found error with a hint.

func ErrRateLimit

func ErrRateLimit(retryAfter int) *Error

ErrRateLimit creates a rate-limit error.

func ErrUsage

func ErrUsage(msg string) *Error

ErrUsage creates a usage error.

func ErrUsageHint

func ErrUsageHint(msg, hint string) *Error

ErrUsageHint creates a usage error with a hint.

func ErrValidation added in v0.4.0

func ErrValidation(messages ...string) *Error

ErrValidation signals that the server rejected the contents of the request (HTTP 422), carrying the messages the model itself produced.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface.

func (*Error) ExitCode

func (e *Error) ExitCode() int

ExitCode returns the appropriate exit code for this error.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the underlying cause for errors.Is/As support.

type EventContentParams added in v0.19.0

type EventContentParams struct {
	// Notes is HEY's calendar_event[description] — Trix rich text, so HTML going in.
	//
	// It does not round-trip. HEY serves the notes back as plain text and omits the key
	// entirely when they are blank, so echoing a read back flattens the markup rather than
	// preserving it. Keeping formatted notes through an update means holding the HTML the
	// caller sent, not the text HEY answered.
	Notes string
	// Location is a plain string. HEY truncates it at 3900 characters rather than refusing it.
	Location string
	// Link is validated as a URL and capped at 2500 characters, so a malformed one is a 422
	// rather than a silent drop.
	//
	// It is not the join_link on a read. HEY derives that by scanning the notes, the location
	// and this for a known meeting service, and it is response-only — there is nothing to
	// submit it with.
	Link string
	// EntryID attaches an email to the event, HEY's calendar_event[entry_id]. A read serves the
	// attachment back as attached_entry, so a caller keeping one passes attached_entry.id here.
	EntryID int64
}

EventContentParams is an event's content, and it is a replacement rather than a patch.

HEY reads these four out of the submitted parameters and then defaults every one of them to nil, so a write that says nothing about a field clears it. There is no way to send a subset: the fields left out of the struct are the fields the event loses. An update therefore has to read the event first and pass back whatever it means to keep — including through UpdateOccurrence, which takes the same parameters.

Title is not in here, and that is not an oversight: HEY leaves the summary alone when it is not submitted, so it stays a *string on an update like the rest of a partial write.

type EventOccurrence added in v0.19.0

type EventOccurrence struct {
	// EventID is the repeating event the occurrence belongs to, HEY's parent_id.
	EventID int64
	// Date is the day the occurrence falls on. Only the calendar date is read.
	Date time.Time
}

EventOccurrence names one day of a repeating calendar event.

A repeating event's days are served as virtual occurrences: they carry an id of 0, the series in parent_id, and their only handle in occurrence_id, which reads "<event id>_<YYYY-MM-DD>". So an occurrence is addressed by the series it belongs to plus the day it falls on, and Update and Delete — which take an id — cannot touch one.

func ParseOccurrenceID added in v0.19.0

func ParseOccurrenceID(occurrenceID string) (EventOccurrence, error)

ParseOccurrenceID reads the occurrence_id HEY serves for a virtual occurrence.

func (EventOccurrence) DateParam added in v0.19.0

func (o EventOccurrence) DateParam() string

DateParam is the date as the occurrence routes take it.

func (EventOccurrence) String added in v0.19.0

func (o EventOccurrence) String() string

String is the occurrence_id again, so an occurrence read out of one can be handed back as one.

type Extenzion added in v0.4.0

type Extenzion struct {
	ID     int64
	Name   string
	AppURL string
}

Extenzion represents an email extenzion.

The id is the extenzion's contact id — the same id the write endpoints take.

type ExtenzionsService added in v0.4.0

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

ExtenzionsService handles email extenzion operations.

Extenzions allow custom email addresses on custom-domain HEY accounts (e.g., sales@yourdomain.com). The endpoints take form-encoded requests. Create and Update post to the .json path, so a current server answers the written extenzion; a server without the JSON branch redirects instead and hands nothing back.

func NewExtenzionsService added in v0.4.0

func NewExtenzionsService(client *Client) *ExtenzionsService

NewExtenzionsService creates a new ExtenzionsService.

func (*ExtenzionsService) Create added in v0.4.0

func (s *ExtenzionsService) Create(ctx context.Context, accountID int64, params CreateExtenzionParams) (extenzion *Extenzion, err error)

Create creates a new extenzion and returns it. A server without the JSON create branch hands nothing back, and the result is then nil.

func (*ExtenzionsService) Delete added in v0.4.0

func (s *ExtenzionsService) Delete(ctx context.Context, accountID int64, extID int64) (err error)

Delete deletes an extenzion.

func (*ExtenzionsService) List added in v0.4.0

func (s *ExtenzionsService) List(ctx context.Context) (result []Extenzion, err error)

List returns the extenzions on the account.

This reads the navigation payload rather than scraping the extenzions page, so it carries only what navigation carries: each extenzion's name and its contact URL.

func (*ExtenzionsService) Update added in v0.4.0

func (s *ExtenzionsService) Update(ctx context.Context, accountID int64, extID int64, params UpdateExtenzionParams) (extenzion *Extenzion, err error)

Update updates an existing extenzion and returns it. A server without the JSON update branch hands nothing back, and the result is then nil.

type FolderPage added in v0.6.1

type FolderPage struct {
	Folder     *generated.FolderWithPostings
	NextPage   string
	TotalCount int
}

FolderPage contains one page of a folder and its pagination state.

type FoldersService added in v0.4.0

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

FoldersService reads folders — the labels you file threads under.

func NewFoldersService added in v0.4.0

func NewFoldersService(client *Client) *FoldersService

NewFoldersService creates a new FoldersService.

func (*FoldersService) Get added in v0.4.0

Get returns a folder and the postings filed in its requested page.

Creating and deleting folders has no JSON surface; use PostingsService.CreateFolder to make one while filing a selection into it.

func (*FoldersService) GetPage added in v0.6.1

func (s *FoldersService) GetPage(ctx context.Context, folderID int64, params *generated.GetFolderParams) (result *FolderPage, err error)

GetPage returns a folder page with its next cursor and total posting count.

type FormResponse added in v0.4.0

type FormResponse struct {
	// Location is the URL from the Location header of the redirect response.
	Location string
	// StatusCode is the HTTP status code (typically 302 or 303).
	StatusCode int
	// Body is the response body, which a redirect leaves empty. Endpoints reached with a
	// .json path answer the created resource here instead of redirecting. It is a string
	// rather than a byte slice so a FormResponse stays comparable.
	Body string
}

FormResponse wraps a response from a form-encoded request that returns a redirect.

func (*FormResponse) ExtractID added in v0.4.0

func (r *FormResponse) ExtractID() (int64, error)

ExtractID parses the last numeric path segment from the Location URL. This is used to extract resource IDs from redirect responses.

type GatingHooks

type GatingHooks interface {
	Hooks
	OnOperationGate(ctx context.Context, op OperationInfo) (context.Context, error)
}

GatingHooks extends Hooks with request gating capability.

type HTTPOptions

type HTTPOptions struct {
	// Timeout is the request timeout (default: 30s).
	Timeout time.Duration

	// MaxRetries is the maximum retry attempts for GET requests (default: 3).
	MaxRetries int

	// BaseDelay is the initial backoff delay (default: 1s).
	BaseDelay time.Duration

	// MaxJitter is the maximum random jitter to add to delays (default: 100ms).
	MaxJitter time.Duration

	// MaxPages is the maximum pages to fetch in GetAll (default: 10000).
	MaxPages int

	// Transport is the HTTP transport to use. If nil, a default transport
	// with sensible connection pooling is created.
	Transport http.RoundTripper

	// MaxResponseBodyBytes is the most a JSON or HTML response body may deliver, in
	// decompressed bytes, before its read fails with an error wrapping ErrResponseTooLarge —
	// success and error responses alike; a refused error body still carries its status. 0
	// or a negative value means DefaultMaxResponseBodyBytes: the cap is always installed.
	// The transport applies it; a client built with WithHTTPClient keeps it only on Get and
	// GetHTML, which bound their own buffering at the same number, not on the service
	// methods.
	//
	// Blob (*/*) and CSV answers are not capped here: GetBlob and GetCSV buffer under the
	// 50 MiB MaxResponseBodyBytes constant instead, and only DownloadBlob streams without
	// a bound.
	MaxResponseBodyBytes int64
}

HTTPOptions configures the HTTP client behavior.

func DefaultHTTPOptions

func DefaultHTTPOptions() HTTPOptions

DefaultHTTPOptions returns HTTPOptions with sensible defaults.

type HabitParams added in v0.4.0

type HabitParams struct {
	Name  string
	Icon  string
	Color string
	Days  []int32
}

HabitParams describes a habit. Days are 0 for Sunday through 6 for Saturday.

type HabitsService

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

HabitsService handles habit tracking operations.

func NewHabitsService

func NewHabitsService(client *Client) *HabitsService

NewHabitsService creates a new HabitsService.

func (*HabitsService) Complete

func (s *HabitsService) Complete(ctx context.Context, day string, habitID int64) (result *generated.Recording, err error)

Complete marks a habit as complete for a given day.

func (*HabitsService) Create added in v0.4.0

func (s *HabitsService) Create(ctx context.Context, params HabitParams) (recording *generated.Recording, err error)

Create starts a new habit and returns it as a recording.

func (*HabitsService) Delete added in v0.4.0

func (s *HabitsService) Delete(ctx context.Context, habitID int64) error

Delete throws a habit away, along with its history. habitID is the recording's id.

func (*HabitsService) Resume added in v0.4.0

func (s *HabitsService) Resume(ctx context.Context, habitID int64) error

Resume puts a paused habit back on the calendar.

func (*HabitsService) Stop added in v0.4.0

func (s *HabitsService) Stop(ctx context.Context, habitID int64) error

Stop pauses a habit, keeping its history but taking it off the calendar.

func (*HabitsService) Uncomplete

func (s *HabitsService) Uncomplete(ctx context.Context, day string, habitID int64) (result *generated.Recording, err error)

Uncomplete marks a habit as incomplete for a given day.

func (*HabitsService) Update added in v0.4.0

func (s *HabitsService) Update(ctx context.Context, habitID int64, params HabitParams) (recording *generated.Recording, err error)

Update edits a habit and returns it as a recording. habitID is the recording's id. Empty fields are left alone.

type Hooks

type Hooks interface {
	OnOperationStart(ctx context.Context, op OperationInfo) context.Context
	OnOperationEnd(ctx context.Context, op OperationInfo, err error, duration time.Duration)
	OnRequestStart(ctx context.Context, info RequestInfo) context.Context
	OnRequestEnd(ctx context.Context, info RequestInfo, result RequestResult)
	OnRetry(ctx context.Context, info RequestInfo, attempt int, err error)
}

Hooks provides observability callbacks for SDK operations.

func NewChainHooks

func NewChainHooks(hooks ...Hooks) Hooks

NewChainHooks creates a ChainHooks from the given hooks.

type IdentityService

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

IdentityService handles identity and navigation operations.

func NewIdentityService

func NewIdentityService(client *Client) *IdentityService

NewIdentityService creates a new IdentityService.

func (*IdentityService) GetIdentity

func (s *IdentityService) GetIdentity(ctx context.Context) (result *generated.Identity, err error)

GetIdentity returns the current user's identity.

func (*IdentityService) GetNavigation

func (s *IdentityService) GetNavigation(ctx context.Context) (result *generated.NavigationResponse, err error)

GetNavigation returns the navigation structure for the current user.

func (*IdentityService) UpdateFirstWeekDay added in v0.23.0

func (s *IdentityService) UpdateFirstWeekDay(ctx context.Context, day time.Weekday) (result time.Weekday, err error)

UpdateFirstWeekDay sets which day the current identity's calendar weeks start on, and returns the day HEY stored.

func (*IdentityService) UpdateTimeFormat added in v0.23.0

func (s *IdentityService) UpdateTimeFormat(ctx context.Context, format TimeFormat) (result TimeFormat, err error)

UpdateTimeFormat sets whether HEY renders times on a 12-hour or 24-hour clock, and returns the format HEY stored.

type JournalPage added in v0.15.0

type JournalPage struct {
	Entries  []generated.Recording
	NextPage string
}

JournalPage contains one page of journal entries and the cursor for the page after it. NextPage is empty on the last page.

type JournalService

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

JournalService handles journal entry operations.

A day has at most one journal entry. HEY answers the entry as a calendar recording carrying the full text (`content`) and the rich-text HTML (`content_html`); a day with no entry answers 204, which the SDK reports as a nil recording.

func NewJournalService

func NewJournalService(client *Client) *JournalService

NewJournalService creates a new JournalService.

func (*JournalService) Get

func (s *JournalService) Get(ctx context.Context, day string) (result *generated.Recording, err error)

Get returns the journal entry for a day (YYYY-MM-DD), or nil when the day has none.

func (*JournalService) GetContent added in v0.3.0

func (s *JournalService) GetContent(ctx context.Context, day string) (content string, err error)

GetContent returns the rich-text HTML of the day's journal entry, or "" when there is none.

func (*JournalService) ListPage added in v0.15.0

func (s *JournalService) ListPage(ctx context.Context, page, query string) (result *JournalPage, err error)

ListPage returns journal entries newest first, optionally filtered by a search query. Pass an empty page for the first page, then the NextPage of each answer.

func (*JournalService) Update

func (s *JournalService) Update(ctx context.Context, day string, content string) (result *generated.Recording, err error)

Update writes the day's journal entry (creating it if needed) and returns it as a recording. Empty content removes the entry, in which case the result is nil.

The HEY API expects the body wrapped as {calendar_journal_entry: {content: "..."}}.

type ListMeta

type ListMeta struct {
	// TotalCount is the total number of items available (from X-Total-Count header).
	// Zero if the header was not present or could not be parsed.
	TotalCount int
}

ListMeta contains pagination metadata from list operations.

type ListedCalendar added in v0.21.0

type ListedCalendar struct {
	Calendar            generated.Calendar `json:"calendar"`
	RecordingChangesURL string             `json:"recording_changes_url"`
	SignedStreamName    string             `json:"signed_stream_name"`
}

ListedCalendar is a calendar as the calendars list serves it, wrapped with what a live follower needs: RecordingChangesURL is where the calendar's recording changes feed starts (read it with CalendarChangesCursorFrom), and SignedStreamName subscribes the calendar's stream over Action Cable — a frame arriving there means the calendar changed, and the name is stable for the calendar's life. The level-1 changes feed's added bucket carries the same shape, so a calendar learned of either way arrives subscribable.

type Match

type Match struct {
	// Operation is the matched API operation name (e.g., "GetBox", "CreateMessage").
	Operation string

	// Operations lists all API operations for the matched pattern, keyed by HTTP method.
	Operations map[string]string

	// Resource is the API resource group (e.g., "Boxes", "Messages").
	Resource string

	// Params contains all named path parameters extracted from the URL.
	Params map[string]string
	// contains filtered or unexported fields
}

Match holds the components extracted from a HEY API URL.

func (*Match) ResourceID

func (m *Match) ResourceID() string

ResourceID returns the last path parameter value (the "primary" resource ID). Returns empty string if no parameters exist.

type MessagesService

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

MessagesService handles message operations.

func NewMessagesService

func NewMessagesService(client *Client) *MessagesService

NewMessagesService creates a new MessagesService.

func (*MessagesService) Create

func (s *MessagesService) Create(ctx context.Context, subject, content string, to, cc, bcc []string) (err error)

Create creates a new message (starts a new thread) and delivers it. The acting sender ID is automatically resolved.

Wire format (MessagesController#create): {acting_sender_id, message: {subject, content}, entry: {addressed: {directly: [...], copied: [...], blindcopied: [...]}}}. Recipient lists are JSON arrays; haystack applies Array() to each kind.

func (*MessagesService) CreateDraft added in v0.22.0

func (s *MessagesService) CreateDraft(ctx context.Context, draft DraftContent) (entryID int64, err error)

CreateDraft saves a new message as a draft instead of delivering it, and answers the draft's entry id — the id GetEdit, UpdateDraft, SendDraft and DeleteDraft take. A draft needs no recipients; whatever it carries is kept for the send.

func (*MessagesService) Get

func (s *MessagesService) Get(ctx context.Context, messageID int64) (result *generated.Message, err error)

Get returns a specific message by ID.

func (*MessagesService) GetEdit added in v0.22.0

func (s *MessagesService) GetEdit(ctx context.Context, entryID int64) (result *generated.MessageEditState, err error)

GetEdit answers a draft's editable state — the subject, the Trix HTML body, the recipients per kind and any scheduled delivery, as the composer would load them.

func (*MessagesService) SendDraft added in v0.22.0

func (s *MessagesService) SendDraft(ctx context.Context, entryID int64, draft DraftContent) error

SendDraft delivers a draft through HEY's undo-delay window. The revision and the delivery are one request, so the draft's final state rides along: subject, body and recipients are replaced with what is sent, exactly as UpdateDraft replaces them. Delivery needs somebody to deliver to, so at least one recipient is required.

The request is never retried, despite the PUT: it triggers a delivery, and a retry after an ambiguous first attempt could send the message twice. An ambiguous failure is the caller's to resolve — read the draft (or the thread) before trying again.

func (*MessagesService) UpdateDraft added in v0.22.0

func (s *MessagesService) UpdateDraft(ctx context.Context, entryID int64, draft DraftContent) error

UpdateDraft revises a draft in place from the whole of draft: the subject, the body and the recipients are replaced with what is sent (empty recipients remove them), and the scheduled delivery is rewritten too — a nil Schedule clears one already set. A trashed draft is silently restored by the revision.

type NoopHooks

type NoopHooks struct{}

NoopHooks is a no-op implementation of Hooks.

func (NoopHooks) OnOperationEnd

func (NoopHooks) OnOperationStart

func (NoopHooks) OnOperationStart(ctx context.Context, _ OperationInfo) context.Context

func (NoopHooks) OnRequestEnd

func (NoopHooks) OnRequestStart

func (NoopHooks) OnRequestStart(ctx context.Context, _ RequestInfo) context.Context

func (NoopHooks) OnRetry

type OccurrenceScope added in v0.19.0

type OccurrenceScope string

OccurrenceScope says how much of a repeating event a write to one of its occurrences reaches. Whichever is chosen, the series' earlier days are left alone; the whole series is reached by Update and Delete on the event id instead.

const (
	// OccurrenceScopeThisEvent changes or removes the named day alone. It is the zero value's
	// meaning too, so a caller who says nothing gets the narrower of the two.
	OccurrenceScopeThisEvent OccurrenceScope = "this_event"
	// OccurrenceScopeThisAndFollowing changes or removes the named day and every one after it.
	// On an update HEY does this by splitting the series: it records a new repeating event
	// starting at this day, cancels the occurrences from here on, and either truncates the old
	// series to the day before or destroys it if this was its first day. The response is still
	// the old occurrence, not the new series, so a caller wanting the new event has to read the
	// period again.
	OccurrenceScopeThisAndFollowing OccurrenceScope = "this_and_following"
)

type OperationInfo

type OperationInfo struct {
	Service      string
	Operation    string
	ResourceType string
	IsMutation   bool
	ResourceID   int64
}

OperationInfo describes a semantic SDK operation.

type PostingChanges added in v0.6.0

type PostingChanges struct {
	Added            []generated.Posting
	Updated          []generated.Posting
	Deleted          []generated.DeletedPosting
	NextPage         *PostingChangesCursor
	NextCursor       *PostingChangesCursor
	FullSyncRequired bool
}

PostingChanges is everything that happened to a box's postings since a cursor.

NextPage is set while this increment has more pages to read now. NextCursor is set on the last page and is where the next read should resume; it is nil when nothing changed, in which case the cursor that produced this page still stands. FullSyncRequired is set when the cursor is too far behind for an increment to carry the difference, and the box has to be read in full instead.

type PostingChangesCursor added in v0.6.0

type PostingChangesCursor struct {
	Since   string
	Version string
	Page    string
	PerPage string
}

PostingChangesCursor is where a read of a box's changes feed starts. Since is an ISO 8601 timestamp with milliseconds and is exclusive; Version is the contract version the caller speaks. A box's PostingChangesUrl carries the pair to begin with — read it with PostingChangesCursorFrom rather than picking the query apart.

func PostingChangesCursorFrom added in v0.6.0

func PostingChangesCursorFrom(changesURL string) (PostingChangesCursor, error)

PostingChangesCursorFrom reads a cursor out of a changes URL the server issued, either a box's PostingChangesUrl or a Link header the feed answered with.

type PostingsService added in v0.2.0

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

PostingsService handles posting-level actions (seen, move, trash, mute).

HEY exposes these as bulk endpoints that take a list of posting IDs, so every method here accepts one or more IDs.

func NewPostingsService added in v0.2.0

func NewPostingsService(client *Client) *PostingsService

NewPostingsService creates a new PostingsService.

func (*PostingsService) AddToBoxGroup added in v0.4.0

func (s *PostingsService) AddToBoxGroup(ctx context.Context, boxID, boxGroupID int64, postingIDs ...int64) (err error)

AddToBoxGroup files one or more postings into an existing Set Aside group.

func (*PostingsService) AllChanges added in v0.6.0

func (s *PostingsService) AllChanges(ctx context.Context, boxID int64, cursor PostingChangesCursor) (*PostingChanges, error)

AllChanges reads a box's posting changes feed from a cursor to its end.

func (*PostingsService) BubbleUpNow added in v0.4.0

func (s *PostingsService) BubbleUpNow(ctx context.Context, postingIDs ...int64) (err error)

BubbleUpNow bubbles one or more postings up right away.

func (*PostingsService) BundleUnseenPage added in v0.26.0

func (s *PostingsService) BundleUnseenPage(ctx context.Context, postingID int64, cursor string) (result *BundlePage, err error)

BundleUnseenPage reads one page of the unseen postings a bundle posting groups (GET /postings/{id}/bundles/unseen). An empty cursor starts at the top; the next page's cursor comes back on the page before it. The posting must be a bundle.

func (*PostingsService) CancelBubbleUp added in v0.4.0

func (s *PostingsService) CancelBubbleUp(ctx context.Context, postingIDs ...int64) (err error)

CancelBubbleUp drops the scheduled bubble up on one or more postings.

func (*PostingsService) Changes added in v0.6.0

func (s *PostingsService) Changes(ctx context.Context, boxID int64, cursor PostingChangesCursor) (result *PostingChanges, err error)

Changes returns one page of a box's posting changes feed.

func (*PostingsService) CreateFolder added in v0.4.0

func (s *PostingsService) CreateFolder(ctx context.Context, name string, postingIDs ...int64) (err error)

CreateFolder creates a folder (label) and files one or more postings into it.

func (*PostingsService) File added in v0.4.0

func (s *PostingsService) File(ctx context.Context, folderID int64, postingIDs ...int64) (err error)

File labels one or more postings with an existing folder.

func (*PostingsService) MarkSeen added in v0.2.0

func (s *PostingsService) MarkSeen(ctx context.Context, postingIDs []int64) (err error)

MarkSeen marks one or more postings as seen/read.

func (*PostingsService) MarkSpam added in v0.4.0

func (s *PostingsService) MarkSpam(ctx context.Context, postingIDs ...int64) (err error)

MarkSpam marks one or more postings as spam (POST /postings/spam).

Past ten postings the server hands the work to a background job, so the call returns before the postings have actually moved.

func (*PostingsService) MarkUnseen added in v0.2.0

func (s *PostingsService) MarkUnseen(ctx context.Context, postingIDs []int64) (err error)

MarkUnseen marks one or more postings as unseen/unread.

func (*PostingsService) Move added in v0.4.0

func (s *PostingsService) Move(ctx context.Context, boxID int64, postingIDs ...int64) (err error)

Move moves one or more postings to the box with the given ID (POST /postings/moves). Box IDs come from Boxes().List.

func (*PostingsService) MoveToBox added in v0.4.0

func (s *PostingsService) MoveToBox(ctx context.Context, kind string, postingIDs ...int64) error

MoveToBox moves one or more postings to the box of the given kind (BoxKindImbox, BoxKindFeed, ...). The kind→ID mapping is resolved once via ListBoxes and cached on the client.

func (*PostingsService) MoveToFeed added in v0.2.0

func (s *PostingsService) MoveToFeed(ctx context.Context, postingIDs ...int64) error

MoveToFeed moves postings to The Feed.

func (*PostingsService) MoveToImbox added in v0.4.0

func (s *PostingsService) MoveToImbox(ctx context.Context, postingIDs ...int64) error

MoveToImbox moves postings to the Imbox.

func (*PostingsService) MoveToPaperTrail added in v0.2.0

func (s *PostingsService) MoveToPaperTrail(ctx context.Context, postingIDs ...int64) error

MoveToPaperTrail moves postings to the Paper Trail.

func (*PostingsService) MoveToReplyLater added in v0.2.0

func (s *PostingsService) MoveToReplyLater(ctx context.Context, postingIDs ...int64) error

MoveToReplyLater moves postings to Reply Later.

func (*PostingsService) MoveToSetAside added in v0.2.0

func (s *PostingsService) MoveToSetAside(ctx context.Context, postingIDs ...int64) error

MoveToSetAside moves postings to Set Aside.

func (*PostingsService) MoveToTrash added in v0.2.0

func (s *PostingsService) MoveToTrash(ctx context.Context, postingIDs ...int64) (err error)

MoveToTrash moves one or more postings to the trash (POST /postings/trash). For shared topics HEY removes your access rather than trashing for everyone.

func (*PostingsService) Mute added in v0.4.0

func (s *PostingsService) Mute(ctx context.Context, postingIDs ...int64) (err error)

Mute mutes one or more postings so their threads stop notifying (POST /postings/mutings).

func (*PostingsService) RemoveFromBoxGroup added in v0.4.0

func (s *PostingsService) RemoveFromBoxGroup(ctx context.Context, postingIDs ...int64) (err error)

RemoveFromBoxGroup takes one or more postings out of whatever Set Aside group they are in.

func (*PostingsService) ScheduleBubbleUp added in v0.24.0

func (s *PostingsService) ScheduleBubbleUp(ctx context.Context, date string, postingIDs ...int64) (err error)

ScheduleBubbleUp schedules one or more postings to bubble up on a date, written YYYY-MM-DD. HEY resurfaces them at its morning hour of that day — in UTC, like every hour HEY reads out of a JSON request. HEY does not refuse a past timestamp — the postings bubble up on the next scheduler run instead.

func (*PostingsService) ScheduleBubbleUpFor added in v0.24.0

func (s *PostingsService) ScheduleBubbleUpFor(ctx context.Context, slot BubbleUpSlot, postingIDs ...int64) (err error)

ScheduleBubbleUpFor schedules one or more postings to bubble up at one of HEY's named slots.

func (*PostingsService) TrashForEveryone added in v0.4.0

func (s *PostingsService) TrashForEveryone(ctx context.Context, postingIDs ...int64) (err error)

TrashForEveryone moves one or more postings to the trash, and on shared topics trashes the thread for everyone on it instead of only dropping your own access.

func (*PostingsService) Unfile added in v0.4.0

func (s *PostingsService) Unfile(ctx context.Context, folderID int64, postingIDs ...int64) (err error)

Unfile removes a label from one or more postings. A folderID of 0 removes every label.

func (*PostingsService) Unmute added in v0.4.0

func (s *PostingsService) Unmute(ctx context.Context, postingIDs ...int64) (err error)

Unmute unmutes one or more postings (DELETE /postings/mutings).

type PublicationsService added in v0.4.0

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

PublicationsService turns a thread into a public web page.

Publishing has no JSON surface: both writes redirect, and the public link only appears on the sharing panel, so Get reads it from there.

func NewPublicationsService added in v0.4.0

func NewPublicationsService(client *Client) *PublicationsService

NewPublicationsService creates a new PublicationsService.

func (*PublicationsService) Create added in v0.4.0

func (s *PublicationsService) Create(ctx context.Context, topicID int64) (result *generated.TopicPublication, err error)

Create publishes a thread and returns its public link.

Answers a forbidden error on accounts that aren't eligible to publish.

func (*PublicationsService) Delete added in v0.4.0

func (s *PublicationsService) Delete(ctx context.Context, topicID int64) error

Delete unpublishes a thread, breaking its public link.

func (*PublicationsService) Get added in v0.4.0

func (s *PublicationsService) Get(ctx context.Context, topicID int64) (result *generated.TopicPublication, err error)

Get reports whether a thread is published and, if it is, its public link.

type RateLimitConfig

type RateLimitConfig struct {
	RequestsPerSecond float64
	BurstSize         int
	RespectRetryAfter bool
	Now               func() time.Time
}

RateLimitConfig configures client-side rate limiting.

func DefaultRateLimitConfig

func DefaultRateLimitConfig() *RateLimitConfig

DefaultRateLimitConfig returns production-ready defaults.

type RecordingChanges added in v0.21.0

type RecordingChanges struct {
	Added            map[string][]generated.Recording
	Updated          map[string][]generated.Recording
	Deleted          []DeletedRecording
	NextPage         *CalendarChangesCursor
	NextCursor       *CalendarChangesCursor
	FullSyncRequired bool
}

RecordingChanges is everything that happened to a calendar's recordings since a cursor. Added and Updated keep the wire's grouping by recordable type key — "Calendar::Event", "Calendar::Habit", "Calendar::Habit::Completion", "Calendar::DayTitle", "Calendar::DayBackground", "Calendar::TimeTrack", "Calendar::Todo", "Calendar::Countdown", "Calendar::JournalEntry" — the server owns that vocabulary. Deleted is one deduplicated slice: the wire groups deletions by type key too, but it repeats the whole deleted collection under every key it groups, so the map shape carries no information beyond each record's own Type — which is authoritative here.

NextPage is set while this increment has more pages to read now. NextCursor is set on the last page and is where the next read should resume; it is nil when nothing changed, in which case the cursor that produced this page still stands. FullSyncRequired is set when the cursor is too far behind for an increment to carry the difference — or speaks a version the feed no longer does — and the calendar has to be read in full instead.

type RepeatFrequency added in v0.19.0

type RepeatFrequency string

RepeatFrequency is how often an event repeats. HEY has no day-of-week parameter, so RepeatEveryWeekday — a hardcoded Monday to Friday — is the only weekday set expressible.

const (
	RepeatEveryDay        RepeatFrequency = "every_day"
	RepeatEveryWeekday    RepeatFrequency = "every_weekday"
	RepeatEveryWeek       RepeatFrequency = "every_week"
	RepeatEveryOtherWeek  RepeatFrequency = "every_other_week"
	RepeatEveryDayOfMonth RepeatFrequency = "every_day_of_month"
	RepeatEveryYear       RepeatFrequency = "every_year"
	// RepeatCustom keeps whatever schedule the event already has instead of naming a new one.
	// It is how a write says the recurrence is none of its business.
	RepeatCustom RepeatFrequency = "custom"
)

type RepeatParams added in v0.19.0

type RepeatParams struct {
	Frequency RepeatFrequency
	Until     RepeatUntil
	// UntilDate is YYYY-MM-DD and is read only when Until is RepeatUntilDate.
	UntilDate string
	// Count is read only when Until is RepeatUntilCount.
	Count int
}

RepeatParams is an event's recurrence.

type RepeatUntil added in v0.19.0

type RepeatUntil string

RepeatUntil says when a recurrence stops.

const (
	RepeatUntilForever RepeatUntil = "forever"
	RepeatUntilDate    RepeatUntil = "date"
	RepeatUntilCount   RepeatUntil = "count"
)

type RequestInfo

type RequestInfo struct {
	Method  string
	URL     string
	Attempt int
}

RequestInfo contains information about an HTTP request.

type RequestResult

type RequestResult struct {
	StatusCode int
	Duration   time.Duration
	Error      error
	FromCache  bool
	Retryable  bool
	RetryAfter int
}

RequestResult contains the result of an HTTP request.

type ResilienceConfig

type ResilienceConfig struct {
	CircuitBreaker *CircuitBreakerConfig
	Bulkhead       *BulkheadConfig
	RateLimit      *RateLimitConfig
}

ResilienceConfig combines all resilience settings.

func DefaultResilienceConfig

func DefaultResilienceConfig() *ResilienceConfig

DefaultResilienceConfig returns production-ready defaults.

type Response

type Response struct {
	Data       json.RawMessage
	StatusCode int
	Headers    http.Header
	FromCache  bool
}

Response wraps an API response.

func (*Response) UnmarshalData

func (r *Response) UnmarshalData(v any) error

UnmarshalData unmarshals the response data into the given value.

type Router

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

Router matches HEY API URLs against the OpenAPI-derived route table.

func DefaultRouter

func DefaultRouter() *Router

DefaultRouter returns a shared Router instance using the embedded route table.

func NewRouter

func NewRouter(tableJSON []byte) (*Router, error)

NewRouter creates a Router from a JSON route table.

func (*Router) MatchPath

func (r *Router) MatchPath(path string) *Match

MatchPath parses a HEY API path and returns the matched route and extracted parameters. Returns nil if the path does not match any known route. The path should be the API path portion (e.g., "/boxes/123" or "/topics/456/entries").

type ScreenOptions added in v0.7.0

type ScreenOptions struct {
	// DesignationBoxID files everything the sender sends into that box rather than the Imbox.
	DesignationBoxID int64
	// Spam marks the topics already waiting as spam and trains the filter on them.
	Spam bool
	// MarkTopicsAsSeen screens the sender in without their waiting mail arriving unread.
	MarkTopicsAsSeen bool
}

ScreenOptions carries what to do beyond setting the status.

type SearchParams added in v0.4.0

type SearchParams struct {
	// Query is the words to search for.
	Query string
	// Page is the 1-based results page. Zero asks for the first.
	Page int

	// Required words must all appear.
	Required string
	// Any is a set of words, at least one of which must appear.
	Any string
	// None words must not appear.
	None string
	// ExactPhrase must appear verbatim.
	ExactPhrase string
	// From narrows by sender, To by recipient, Subject by subject line.
	From    string
	To      string
	Subject string
	// Date is "last_7_days", "last_30_days", "last_90_days" or a four-digit year.
	Date string
	// In narrows to a box: "imbox", "feed", "papertrail" or "trash".
	In string
	// Label narrows to a folder name.
	Label string
	// Attachment narrows by attachment kind, or "any".
	Attachment string
}

SearchParams describes an advanced search. Query is the free-text part; the rest map onto the refine[...] parameters the advanced search form submits.

type SearchResults added in v0.10.0

type SearchResults struct {
	Result   *generated.AdvancedSearchResult
	NextPage int
}

SearchResults contains one page of matches and the number of the page after it, zero once there is none. Search numbers its pages rather than cursoring them, so the next page is followed by passing that number back as SearchParams.Page.

type SearchService

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

SearchService searches mail.

HEY has no JSON search endpoint — /search and /advanced_search render HTML — so results are read off the advanced search page. Only the refine options are JSON, via Filters.

func NewSearchService

func NewSearchService(client *Client) *SearchService

NewSearchService creates a new SearchService.

func (*SearchService) Filters added in v0.4.0

func (s *SearchService) Filters(ctx context.Context) (result *generated.AdvancedSearchFilters, err error)

Filters returns the options the advanced search refine form offers: boxes, date ranges, labels and attachment kinds.

func (*SearchService) Search

Search runs an advanced search and returns the matching threads, grouped by topic as the search page shows them: the topic, your posting of it, and the entries that matched (summaries; read a message with Messages().Get). The next page, if any, is followed by passing Page.

func (*SearchService) SearchPage added in v0.10.0

func (s *SearchService) SearchPage(ctx context.Context, params SearchParams) (results *SearchResults, err error)

SearchPage runs the same search as Search and also answers which page comes next, so a caller walking the results is told when it has reached the last of them rather than having to ask for a page that turns out to be empty.

type SnippetsService added in v0.4.0

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

SnippetsService handles snippets — reusable bits of text for the composer.

Snippets have no JSON surface: every write redirects and the list is HTML.

func NewSnippetsService added in v0.4.0

func NewSnippetsService(client *Client) *SnippetsService

NewSnippetsService creates a new SnippetsService.

func (*SnippetsService) Create added in v0.4.0

func (s *SnippetsService) Create(ctx context.Context, name, content string) error

func (*SnippetsService) Delete added in v0.4.0

func (s *SnippetsService) Delete(ctx context.Context, snippetID int64) error

Delete throws a snippet away.

func (*SnippetsService) List added in v0.4.0

func (s *SnippetsService) List(ctx context.Context) (result []generated.Snippet, err error)

List returns the snippets, alphabetically, with their content as text and as HTML.

func (*SnippetsService) Update added in v0.4.0

func (s *SnippetsService) Update(ctx context.Context, snippetID int64, name, content string) error

Update edits a snippet. Empty fields are left alone.

type StaticTokenProvider

type StaticTokenProvider struct {
	Token string
}

StaticTokenProvider provides a fixed token (e.g., from HEY_TOKEN env var).

func (*StaticTokenProvider) AccessToken

func (p *StaticTokenProvider) AccessToken(ctx context.Context) (string, error)

AccessToken returns the static token.

type StickiesService added in v0.4.0

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

StickiesService handles the stickies board.

func NewStickiesService added in v0.4.0

func NewStickiesService(client *Client) *StickiesService

NewStickiesService creates a new StickiesService.

func (*StickiesService) Create added in v0.4.0

func (s *StickiesService) Create(ctx context.Context, body string, size string) (result *generated.Sticky, err error)

Create writes a new sticky. An empty size leaves the server default in place.

func (*StickiesService) Delete added in v0.4.0

func (s *StickiesService) Delete(ctx context.Context, stickyID int64) error

Delete throws a sticky away.

func (*StickiesService) List added in v0.4.0

func (s *StickiesService) List(ctx context.Context, limit int) (result *generated.ListStickiesResponseContent, err error)

List returns the stickies in board order. A limit of zero asks for the server default, which is also its maximum of 100.

func (*StickiesService) Move added in v0.4.0

func (s *StickiesService) Move(ctx context.Context, stickyID int64, position int) error

Move repositions a sticky on the board. Positions run from zero to MaxStickyPosition.

func (*StickiesService) Update added in v0.4.0

func (s *StickiesService) Update(ctx context.Context, stickyID int64, body string, size string) (result *generated.Sticky, err error)

Update edits a sticky. Empty fields are left alone.

type TimeFormat added in v0.23.0

type TimeFormat string

TimeFormat is the clock HEY renders times in.

const (
	TimeFormatTwelveHour     TimeFormat = "twelve_hour"
	TimeFormatTwentyFourHour TimeFormat = "twenty_four_hour"
)

type TimeTrackPage added in v0.20.0

type TimeTrackPage struct {
	TimeTracks []generated.Recording
	Categories []generated.TimeTrackCategory
	NextPage   string
}

TimeTrackPage is one page of tracked time: the completed tracks, the calendar's categories, and the cursor for the page after this one.

Categories is the whole category list rather than the ones this page happens to use, because the index serves it for the filter — so a caller offering the filter never needs Categories() as well.

type TimeTracksService

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

TimeTracksService handles time tracking operations.

func NewTimeTracksService

func NewTimeTracksService(client *Client) *TimeTracksService

NewTimeTracksService creates a new TimeTracksService.

func (*TimeTracksService) Categories added in v0.4.0

func (s *TimeTracksService) Categories(ctx context.Context) (result []generated.TimeTrackCategory, err error)

Categories returns the calendar's time track categories, alphabetically.

func (*TimeTracksService) Create added in v0.4.0

Create records a stretch of time that has already finished.

JSON callers send the fields flat; the server wraps them itself.

func (*TimeTracksService) CreateCategory added in v0.4.0

func (s *TimeTracksService) CreateCategory(ctx context.Context, title string) error

CreateCategory adds a time track category.

func (*TimeTracksService) Delete added in v0.4.0

func (s *TimeTracksService) Delete(ctx context.Context, timeTrackID int64) error

Delete throws a time track away. timeTrackID is the recording's id.

func (*TimeTracksService) DeleteCategory added in v0.4.0

func (s *TimeTracksService) DeleteCategory(ctx context.Context, categoryID int64) error

DeleteCategory removes a time track category. The tracks filed under it stay, uncategorized.

func (*TimeTracksService) Export added in v0.4.0

func (s *TimeTracksService) Export(ctx context.Context) (result []byte, err error)

Export returns every completed time track as CSV, newest first, with the columns Start, End, Duration, Category and Notes.

func (*TimeTracksService) GetOngoing

func (s *TimeTracksService) GetOngoing(ctx context.Context) (result *generated.Recording, err error)

GetOngoing returns the ongoing time track, or nil if none is active. Per ADR-004, a 404 response is treated as "no active track" rather than an error.

func (*TimeTracksService) List added in v0.20.0

List returns a page of tracked time: completed tracks only, newest-ended first, with the calendar's categories alongside them. Pass nil params for the first page, or set CategoryId to narrow the list to one category — an id the calendar has no category for is a 404.

A running track is not in this list; GetOngoing answers that.

List drops the cursor for the next page. Walk the list with ListPage instead.

func (*TimeTracksService) ListPage added in v0.20.0

func (s *TimeTracksService) ListPage(ctx context.Context, params *generated.ListTimeTracksParams) (result *TimeTrackPage, err error)

ListPage returns the same page as List along with the cursor for the page after it, so a caller walking the list is told when it has reached the end of it.

An empty NextPage means there is no page after this one: geared_pagination only sends the Link header while there is more to read, so the last page carries no cursor and that is not an error. An empty page ends the list whatever cursor came with it.

func (*TimeTracksService) Start

func (s *TimeTracksService) Start(ctx context.Context) (result *generated.Recording, err error)

Start starts a new time track and returns it as a recording.

It takes no parameters: HEY ignores the request body here and starts a track with defaults. Notes and a category come later, with Update or StopAndFile, both of which also stop the track. A 409 means a track is already ongoing.

func (*TimeTracksService) Stop

func (s *TimeTracksService) Stop(ctx context.Context, timeTrackID int64) error

Stop stops an ongoing time track by setting ends_at to the current time. It reports itself to hooks as StopTimeTrack, distinct from UpdateTimeTrack, so a gating policy can allow one without the other; the request itself is the same PUT that Update sends.

func (*TimeTracksService) StopAndFile added in v0.20.0

func (s *TimeTracksService) StopAndFile(ctx context.Context, timeTrackID int64, categoryTitle string) error

StopAndFile stops a time track and files it under a category in the one request, creating the category if HEY has none by that name. An empty categoryTitle stops the track without filing it, which is what Stop does.

Filing is only ever part of stopping: the server completes a track on every update, so there is no such thing as setting a category on a track that keeps running.

func (*TimeTracksService) Update

func (s *TimeTracksService) Update(ctx context.Context, timeTrackID int64, body generated.UpdateTimeTrackJSONRequestBody) (result *generated.Recording, err error)

Update updates an existing time track.

The body already carries the {calendar_time_track: {...}} wrapper the API expects.

Every update completes the track, whether or not the body sets ends_at, so there is no adjusting a running track: updating one stops it. Set CategoryTitle to file the track under a category; the Category field is ignored by the server.

func (*TimeTracksService) UpdateCategory added in v0.4.0

func (s *TimeTracksService) UpdateCategory(ctx context.Context, categoryID int64, title string) error

UpdateCategory renames a time track category.

type TodoChanges added in v0.14.0

type TodoChanges struct {
	Title    string
	StartsAt string // Date string (YYYY-MM-DD)
	Focused  *bool
}

TodoChanges is what an edit changes about a todo. A zero field is left alone: the server applies what it is sent and keeps the rest, so a rename carries a title and says nothing about the day.

type TokenProvider

type TokenProvider interface {
	AccessToken(ctx context.Context) (string, error)
}

TokenProvider is the interface for obtaining access tokens.

type TokenRefresher added in v0.11.0

type TokenRefresher interface {
	Refresh(ctx context.Context) error
}

TokenRefresher renews the credentials a request is authenticated with, which is what lets a 401 be retried rather than surfaced. AuthManager is one, and so is any AuthStrategy or TokenProvider a caller brings that can renew what it hands out — a client that keeps its credentials somewhere else is exactly the case that needs this, since it has no AuthManager for the client to recognise.

type TopicEntryPage added in v0.11.0

type TopicEntryPage struct {
	Entries  []generated.Entry
	NextPage string
}

TopicEntryPage contains one page of a topic's entries and the cursor for the page after it. NextPage is empty on the last page, which is how a caller walking a thread is told it has read all of it.

type TopicsService

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

TopicsService handles topic operations.

func NewTopicsService

func NewTopicsService(client *Client) *TopicsService

NewTopicsService creates a new TopicsService.

func (*TopicsService) EmptySpam added in v0.4.0

func (s *TopicsService) EmptySpam(ctx context.Context) error

EmptySpam deletes everything in the spam box. The server does this synchronously, so a large spam box can take a while.

func (*TopicsService) EmptyTrash added in v0.4.0

func (s *TopicsService) EmptyTrash(ctx context.Context) error

EmptyTrash deletes everything in the trash. The server does this synchronously, so a large trash can take a while.

func (*TopicsService) Get

func (s *TopicsService) Get(ctx context.Context, topicID int64) (result *generated.Topic, err error)

Get returns a specific topic by ID.

func (*TopicsService) GetEntries

GetEntries returns entries for a specific topic.

The entry index is paginated by geared_pagination, so the page in params is a cursor out of the previous answer's Link header rather than an offset — a number is ignored and answered with the first page. This throws that header away; use GetEntriesPage to walk the thread.

func (*TopicsService) GetEntriesPage added in v0.11.0

func (s *TopicsService) GetEntriesPage(ctx context.Context, topicID int64, page string) (result *TopicEntryPage, err error)

GetEntriesPage answers the same entries as GetEntries along with the cursor for the page after it, so a caller walking a thread follows HEY's own ordering rather than guessing page numbers geared_pagination does not understand.

Pass an empty page for the first page, then the NextPage of each answer.

func (*TopicsService) GetEverything

func (s *TopicsService) GetEverything(ctx context.Context, params *generated.GetEverythingTopicsParams) (result *generated.TopicListResponse, err error)

GetEverything returns all topics.

func (*TopicsService) GetSent

GetSent returns sent topics.

func (*TopicsService) GetSpam

GetSpam returns spam topics.

func (*TopicsService) GetTrash

GetTrash returns trash topics.

func (*TopicsService) MarkHam added in v0.4.0

func (s *TopicsService) MarkHam(ctx context.Context, topicID int64) error

MarkHam rescues a topic from spam. Every other spam topic from the same sender comes with it.

func (*TopicsService) Move added in v0.4.0

func (s *TopicsService) Move(ctx context.Context, topicID int64, boxID int64) error

Move moves a topic to another box.

The server answers 204 without moving anything when the acting user has no posting for the topic, so a success here is not proof the topic moved.

func (*TopicsService) Restore added in v0.4.0

func (s *TopicsService) Restore(ctx context.Context, topicID int64) error

Restore brings a topic back from the trash or the catch-all.

func (*TopicsService) Trash added in v0.4.0

func (s *TopicsService) Trash(ctx context.Context, topicID int64, confirmDestroy bool) error

Trash moves a topic to the trash.

Shared topics redirect to a confirmation page unless confirmDestroy is set, so pass it whenever the topic might be shared.

type UpdateCalendarEventOccurrenceParams added in v0.19.0

type UpdateCalendarEventOccurrenceParams struct {
	UpdateCalendarEventParams
}

UpdateCalendarEventOccurrenceParams contains the parameters for updating one occurrence of a repeating event. They are a whole-event update's, read the same way but for Repeat.

A nil Repeat leaves a whole event's recurrence alone. Here it would end it: HEY reads an occurrence update that names no frequency as "stop repeating", drops the series' schedule and cancels every other occurrence. So UpdateOccurrence sends RepeatCustom for a nil one, which keeps the schedule the series already has — the recurrence is not usually the business of an update to one day of it. Naming a Repeat means changing the series' schedule on purpose.

type UpdateCalendarEventParams added in v0.4.0

type UpdateCalendarEventParams struct {
	// CalendarID moves the event to another calendar. An update takes the same calendar as a
	// create does, which is how the web app's calendar select relocates an event.
	//
	// It has to be a calendar the identity can file on — one it owns or shares, and not a
	// subscription. The personal calendar is the one that catches you out: it is in the list
	// Identity serves, and filing on it answers 404 all the same.
	CalendarID *int64
	Title      *string
	StartsAt   *string
	EndsAt     *string
	AllDay     *bool
	StartTime  *string
	EndTime    *string
	// StartTimeZone and EndTimeZone are the zones the clock times are written in, as on a
	// create. Empty strings say the times are UTC and clear the zones the event was saved
	// with; nil leaves them out of the request, which HEY also reads as clearing them.
	StartTimeZone *string
	EndTimeZone   *string
	// TimeZone names one zone for both ends.
	//
	// Deprecated: use StartTimeZone and EndTimeZone. It stands in for whichever of them is
	// nil, so a caller that only ever wanted one zone keeps working.
	TimeZone *string
	// Reminders is resend-or-lose-it, like the zones. HEY reads the list on every write and
	// unschedules everything when it is empty, so an update that leaves it out removes the
	// reminders the event had. Several durations go in one write and HEY de-duplicates them;
	// only the list matching the event's all-day flag is read.
	Reminders []time.Duration
	// Content is the notes, location, link and attached entry, and it is a replacement rather
	// than a patch — every field left empty is cleared on the event. See EventContentParams
	// before using it: keeping any of the four means reading the event and passing it back.
	Content EventContentParams
	// Attendees replaces the guest list. Nil leaves it alone; an empty non-nil slice removes
	// every guest. See setAttendees for what submitting it commits the caller to.
	Attendees []string
	// Highlighted circles or uncircles the event, HEY's "Circle event". Nil leaves it as it is.
	Highlighted *bool
	// Countdown is resend-or-lose-it too: the zero value deletes the event's countdown, because
	// that is what HEY does with a write that names no countdown value.
	Countdown CountdownParams
	// Repeat changes the recurrence. Nil leaves it untouched on a whole-event update — but not
	// on an occurrence update, where HEY reads silence as "stop repeating"; see
	// UpdateCalendarEventOccurrenceParams.
	Repeat *RepeatParams
}

UpdateCalendarEventParams contains the parameters for updating a calendar event. The pointer fields are a partial update: only the non-nil ones are sent, and the rest are left as they are.

The value fields are not, and the reason is on HEY's side. It reads the zones, the content fields, the reminders and the countdown out of the submitted parameters on every write and defaults each of them to nothing, so an update saying nothing about one clears it. Those are marked below; a caller keeping any of them has to read the event and send them back.

type UpdateCollectionParams added in v0.4.0

type UpdateCollectionParams struct {
	Name    string
	Summary string
}

UpdateCollectionParams contains the parameters for editing a collection. Empty fields are left alone.

type UpdateExtenzionParams added in v0.4.0

type UpdateExtenzionParams struct {
	// Name is the new extenzion name. Empty string means no change.
	Name string
	// Members is the new list of member email addresses. Replaces all existing members.
	// nil means no change.
	Members []string
}

UpdateExtenzionParams contains the parameters for updating an extenzion.

type Workflow added in v0.4.0

type Workflow struct {
	ID          int64
	Name        string
	AccountName string
}

Workflow is a board of threads.

type WorkflowsService added in v0.4.0

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

WorkflowsService handles workflows — kanban-style boards of threads.

Workflows have no JSON surface beyond the autocomplete endpoint that enumerates them, so writes are form posts and stage names are read off the workflow page.

func NewWorkflowsService added in v0.4.0

func NewWorkflowsService(client *Client) *WorkflowsService

NewWorkflowsService creates a new WorkflowsService.

func (*WorkflowsService) Create added in v0.4.0

func (s *WorkflowsService) Create(ctx context.Context, name string, accountID int64) error

Create adds a workflow. accountID of zero leaves the server to pick your first account.

func (*WorkflowsService) CreateStage added in v0.4.0

func (s *WorkflowsService) CreateStage(ctx context.Context, workflowID int64) error

CreateStage adds a column to a workflow. The server names it "Untitled"; rename it with UpdateStage.

func (*WorkflowsService) Delete added in v0.4.0

func (s *WorkflowsService) Delete(ctx context.Context, workflowID int64) error

Delete throws a workflow away.

func (*WorkflowsService) DeleteStage added in v0.4.0

func (s *WorkflowsService) DeleteStage(ctx context.Context, workflowID, stageID int64) error

DeleteStage removes a workflow column.

func (*WorkflowsService) Get added in v0.4.0

func (s *WorkflowsService) Get(ctx context.Context, workflowID int64) (result *generated.Workflow, err error)

Get returns a workflow with its stages in position order.

func (*WorkflowsService) List added in v0.4.0

func (s *WorkflowsService) List(ctx context.Context, accountID int64) (result []Workflow, err error)

List returns the workflows on an account.

The autocomplete endpoint answers bare [id, name, account name] arrays, and answers 304 to a conditional request — the SDK never sends one, so this always comes back populated.

func (*WorkflowsService) MoveTopic added in v0.12.0

func (s *WorkflowsService) MoveTopic(ctx context.Context, topicID, workflowID, stageID int64) error

MoveTopic moves a staged topic to another workflow stage.

func (*WorkflowsService) StageTopic added in v0.4.0

func (s *WorkflowsService) StageTopic(ctx context.Context, topicID, workflowID, stageID int64) error

StageTopic adds a topic to a workflow in the selected stage. HEY creates the workflow membership before selecting the stage, so a stage-selection error leaves the topic in the workflow's first stage.

func (*WorkflowsService) Stages added in v0.4.0

func (s *WorkflowsService) Stages(ctx context.Context, workflowID int64) ([]generated.WorkflowStage, error)

Stages returns a workflow's stages in position order.

func (*WorkflowsService) UnstageTopic added in v0.4.0

func (s *WorkflowsService) UnstageTopic(ctx context.Context, topicID, workflowID int64) error

UnstageTopic takes a topic back off a workflow.

func (*WorkflowsService) Update added in v0.4.0

func (s *WorkflowsService) Update(ctx context.Context, workflowID int64, name string) error

Update renames a workflow.

func (*WorkflowsService) UpdateStage added in v0.4.0

func (s *WorkflowsService) UpdateStage(ctx context.Context, workflowID, stageID int64, name string) error

UpdateStage renames a workflow column.

type WorldService added in v0.4.0

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

WorldService handles HEY World — the blog you write by sending an email.

None of it is JSON: posts are created by emailing world@hey.com, edits redirect, and the subscriber list is a CSV stream.

func NewWorldService added in v0.4.0

func NewWorldService(client *Client) *WorldService

NewWorldService creates a new WorldService.

func (*WorldService) Delete added in v0.4.0

func (s *WorldService) Delete(ctx context.Context, token string) error

Delete takes a post off HEY World.

func (*WorldService) ExportSubscribers added in v0.4.0

func (s *WorldService) ExportSubscribers(ctx context.Context, listEmailAddress string) (result []byte, err error)

ExportSubscribers returns the confirmed subscribers of a HEY World list as CSV, with the columns email_address and subscribed_at. The list is named by its author's email address.

func (*WorldService) ImportSubscribers added in v0.4.0

func (s *WorldService) ImportSubscribers(ctx context.Context, listEmailAddress, filename string, csv []byte) error

ImportSubscribers uploads a CSV of subscribers to a HEY World list.

func (*WorldService) Publish added in v0.4.0

func (s *WorldService) Publish(ctx context.Context, subject, content string) (token string, err error)

Publish writes a HEY World post by sending a message to world@hey.com, and returns the post's token.

func (*WorldService) Update added in v0.4.0

func (s *WorldService) Update(ctx context.Context, token, subject, content string) error

Update edits a published post. Empty fields are left alone.

Directories

Path Synopsis
Package oauth provides OAuth 2.0 discovery, token exchange, and refresh functionality.
Package oauth provides OAuth 2.0 discovery, token exchange, and refresh functionality.

Jump to

Keyboard shortcuts

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