clockify

package
v1.2.1-rc.2 Latest Latest
Warning

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

Go to latest
Published: May 9, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ListAll

func ListAll[T any](ctx context.Context, c *Client, path string, baseQuery map[string]string) ([]T, error)

ListAll fetches every page into a single slice, bounded by the default pagination row cap.

func ListAllFunc added in v1.2.1

func ListAllFunc[T any](ctx context.Context, c *Client, path string, baseQuery map[string]string, onPage func([]T) error) error

ListAllFunc scans pages and invokes onPage for each non-empty page without retaining earlier pages.

func ListAllFuncWithOptions

func ListAllFuncWithOptions[T any](ctx context.Context, c *Client, path string, baseQuery map[string]string, opts ListAllOptions, onPage func([]T) error) error

ListAllFuncWithOptions scans pages using opts and invokes onPage for each non-empty page without retaining earlier pages.

func ListAllWithOptions

func ListAllWithOptions[T any](ctx context.Context, c *Client, path string, baseQuery map[string]string, opts ListAllOptions) ([]T, error)

ListAllWithOptions fetches every page into a single slice using opts.

Types

type APIError

type APIError struct {
	Method     string
	Path       string
	StatusCode int
	Status     string
	Body       string
	RetryAfter time.Duration
}

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Sanitized

func (e *APIError) Sanitized() string

Sanitized returns the error string without the upstream response body, suitable for hosted/shared deployments where the body might leak per-tenant information across tenants. Server-side logs still call Error() so operators can see the full diagnostic; the sanitised form is only what we hand to the MCP client.

type Client

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

func NewClient

func NewClient(apiKey, baseURL string, timeout time.Duration, maxRetries int) *Client

func (*Client) Close

func (c *Client) Close()

Close releases idle connections held by the client.

func (*Client) Delete

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

func (*Client) DeleteReports

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

DeleteReports performs a DELETE against the reports host.

func (*Client) DeleteWithQuery

func (c *Client) DeleteWithQuery(ctx context.Context, path string, query map[string]string) error

func (*Client) Get

func (c *Client) Get(ctx context.Context, path string, query map[string]string, out any) error

func (*Client) GetReports

func (c *Client) GetReports(ctx context.Context, path string, query map[string]string, out any) error

GetReports performs a GET against the reports host. Use this for shared-report endpoints; everything else should stay on Get.

func (*Client) GetReportsRaw added in v1.2.1

func (c *Client) GetReportsRaw(ctx context.Context, path string, query map[string]string) (*RawResponse, error)

GetReportsRaw is the binary-aware sibling of GetReports. It runs the same retry/tracing/metrics pipeline but skips the JSON unmarshal, exposing the raw body bytes and response headers so callers can inspect Content-Type and Content-Disposition. Use for export endpoints; use GetReports for JSON-shaped reads.

func (*Client) Patch

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

func (*Client) Post

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

func (*Client) PostMultipart

func (c *Client) PostMultipart(ctx context.Context, path string, form url.Values, out any) error

PostMultipart performs a POST with a multipart/form-data body. Each form key maps to one or more values; multi-value keys are written as repeated form fields under the same name (the encoding the Clockify expense endpoints use for fields like changeFields). No file upload support — the expense endpoints accept absent file fields with an empty fileId, so callers don't currently need it.

func (*Client) PostReports

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

PostReports performs a POST against the reports host.

func (*Client) Put

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

func (*Client) PutMultipart

func (c *Client) PutMultipart(ctx context.Context, path string, form url.Values, out any) error

PutMultipart performs a PUT with a multipart/form-data body. Same encoding rules as PostMultipart.

func (*Client) PutReports

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

PutReports performs a PUT against the reports host.

func (*Client) ReportsBaseURL

func (c *Client) ReportsBaseURL() string

ReportsBaseURL returns the base URL for endpoints that live on Clockify's reports host (reports.api.clockify.me/v1). The reports API is a separate host from api.clockify.me — hitting the reports paths on the primary host returns 404 ("No static resource"), and hitting them on the reports host with the /api/v1 prefix is also 404. See findings/shared-reports.md.

Derivation: when the primary base URL matches the canonical production host, swap to reports.api.clockify.me and drop the /api segment. Otherwise (test stubs, custom proxies, on-prem mirrors), return the primary base URL unchanged so existing fixtures continue to work without per-test wiring.

func (*Client) SetUserAgent

func (c *Client) SetUserAgent(ua string)

SetUserAgent sets the User-Agent string sent with every request.

type ClientEntity

type ClientEntity struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	Address      string `json:"address,omitempty"`
	Archived     bool   `json:"archived,omitempty"`
	CCEmails     any    `json:"ccEmails,omitempty"`
	CurrencyCode string `json:"currencyCode,omitempty"`
	CurrencyID   string `json:"currencyId,omitempty"`
	Email        string `json:"email,omitempty"`
	Note         string `json:"note,omitempty"`
	WorkspaceID  string `json:"workspaceId,omitempty"`
}

type ListAllOptions

type ListAllOptions struct {
	// MaxRows bounds total decoded rows before ListAll/ListAllFunc fail
	// closed. 0 uses the default production cap.
	MaxRows int
}

type PaginationCapError

type PaginationCapError struct {
	Path        string
	RowsScanned int
	MaxRows     int
	Page        int
	PageSize    int
}

PaginationCapError reports that a paginated scan exceeded its row cap.

func (*PaginationCapError) Error

func (e *PaginationCapError) Error() string

type Project

type Project struct {
	ID             string `json:"id"`
	Name           string `json:"name"`
	ClientID       string `json:"clientId,omitempty"`
	ClientName     string `json:"clientName,omitempty"`
	Color          string `json:"color,omitempty"`
	Archived       bool   `json:"archived"`
	Billable       bool   `json:"billable,omitempty"`
	BudgetEstimate any    `json:"budgetEstimate,omitempty"`
	CostRate       any    `json:"costRate,omitempty"`
	Duration       string `json:"duration,omitempty"`
	Estimate       any    `json:"estimate,omitempty"`
	EstimateReset  any    `json:"estimateReset,omitempty"`
	HourlyRate     any    `json:"hourlyRate,omitempty"`
	Memberships    any    `json:"memberships,omitempty"`
	Note           string `json:"note,omitempty"`
	Public         bool   `json:"public,omitempty"`
	Template       bool   `json:"template,omitempty"`
	TimeEstimate   any    `json:"timeEstimate,omitempty"`
	WorkspaceID    string `json:"workspaceId,omitempty"`
}

type RawResponse

type RawResponse struct {
	Header http.Header
	Body   []byte
}

RawResponse is the binary-aware envelope returned by GetReportsRaw — the raw response bytes plus enough header context for callers to recover Content-Type and Content-Disposition (filename). Used by the shared-reports export endpoint where the upstream returns binary (PDF/XLSX) or non-JSON text (CSV).

type Tag

type Tag struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Archived    bool   `json:"archived,omitempty"`
	WorkspaceID string `json:"workspaceId,omitempty"`
}

type Task

type Task struct {
	ID             string   `json:"id"`
	Name           string   `json:"name"`
	ProjectID      string   `json:"projectId"`
	AssigneeID     string   `json:"assigneeId,omitempty"`
	AssigneeIDs    []string `json:"assigneeIds,omitempty"`
	Billable       bool     `json:"billable,omitempty"`
	BudgetEstimate int64    `json:"budgetEstimate,omitempty"`
	CostRate       any      `json:"costRate,omitempty"`
	Duration       string   `json:"duration,omitempty"`
	Estimate       string   `json:"estimate,omitempty"`
	HourlyRate     any      `json:"hourlyRate,omitempty"`
	Status         string   `json:"status,omitempty"`
	UserGroupIDs   []string `json:"userGroupIds,omitempty"`
}

type TimeEntry

type TimeEntry struct {
	ID                string       `json:"id"`
	Description       string       `json:"description"`
	ProjectID         string       `json:"projectId"`
	ProjectName       string       `json:"projectName,omitempty"`
	TaskID            string       `json:"taskId,omitempty"`
	TagIDs            []string     `json:"tagIds,omitempty"`
	Billable          bool         `json:"billable,omitempty"`
	CostRate          any          `json:"costRate,omitempty"`
	CustomFieldValues any          `json:"customFieldValues,omitempty"`
	HourlyRate        any          `json:"hourlyRate,omitempty"`
	IsLocked          bool         `json:"isLocked,omitempty"`
	KioskID           string       `json:"kioskId,omitempty"`
	Type              string       `json:"type,omitempty"`
	UserID            string       `json:"userId,omitempty"`
	WorkspaceID       string       `json:"workspaceId,omitempty"`
	TimeInterval      TimeInterval `json:"timeInterval"`
}

func (TimeEntry) DurationSeconds

func (e TimeEntry) DurationSeconds() int64

func (TimeEntry) EndTime

func (e TimeEntry) EndTime() (time.Time, error)

func (TimeEntry) IsRunning

func (e TimeEntry) IsRunning() bool

func (TimeEntry) StartTime

func (e TimeEntry) StartTime() (time.Time, error)

type TimeInterval

type TimeInterval struct {
	Start    string `json:"start"`
	End      string `json:"end,omitempty"`
	Duration string `json:"duration,omitempty"`
}

type User

type User struct {
	ID               string `json:"id"`
	Name             string `json:"name"`
	Email            string `json:"email"`
	ActiveWorkspace  string `json:"activeWorkspace,omitempty"`
	CustomFields     any    `json:"customFields,omitempty"`
	DefaultWorkspace string `json:"defaultWorkspace,omitempty"`
	Memberships      any    `json:"memberships,omitempty"`
	ProfilePicture   string `json:"profilePicture,omitempty"`
	Settings         any    `json:"settings,omitempty"`
	Status           string `json:"status,omitempty"`
}

type Workspace

type Workspace struct {
	ID                      string   `json:"id"`
	Name                    string   `json:"name"`
	CakeOrganizationID      string   `json:"cakeOrganizationId,omitempty"`
	CostRate                any      `json:"costRate,omitempty"`
	Currencies              any      `json:"currencies,omitempty"`
	FeatureSubscriptionType string   `json:"featureSubscriptionType,omitempty"`
	Features                []string `json:"features,omitempty"`
	HourlyRate              any      `json:"hourlyRate,omitempty"`
	ImageURL                string   `json:"imageUrl,omitempty"`
	Memberships             any      `json:"memberships,omitempty"`
	Subdomain               any      `json:"subdomain,omitempty"`
	WorkspaceSettings       any      `json:"workspaceSettings,omitempty"`
}

Jump to

Keyboard shortcuts

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