Documentation
¶
Overview ¶
Package warmbly is the official Go SDK for the Warmbly API.
Warmbly is a cold-outreach and mailbox-warmup platform. This package is a typed client for the whole customer-facing v1 surface; the gateway subpackage streams the same workspace's events over a websocket.
Installation ¶
go get github.com/warmbly/warmbly-go@latest
Authentication ¶
Three credentials reach three different slices of the API:
- API keys (prefixed "wmbly_") for server-to-server access scoped to one workspace. Create a client with WithAPIKey.
- OAuth 2.1 access tokens (prefixed "wmblyo_") for an application acting for a user. Run the authorization-code or client-credentials flow with OAuth2Config or ClientCredentialsConfig, then pass the token with WithAccessToken or WithTokenSource.
- Session tokens from AuthService.Login for the routes a long-lived key deliberately cannot reach: workspace governance, billing and the AI assistant. An API key on one of those gets a clean ErrUnauthorized.
Quick start ¶
client, err := warmbly.New(warmbly.WithAPIKey("wmbly_..."))
if err != nil {
log.Fatal(err)
}
page, err := client.Campaigns.List(ctx, nil)
if err != nil {
log.Fatal(err)
}
for campaign, err := range page.All(ctx) {
if err != nil {
log.Fatal(err)
}
fmt.Println(campaign.Name)
}
Shape of the API ¶
Every resource group is a service on the Client: Client.Emails, Client.Campaigns, Client.Contacts, Client.Unibox, Client.CRM and the rest. Each method takes a context, then its parameters, then a variadic list of RequestOption.
Methods that return one record return it alongside the Response, so rate-limit state and the request id stay reachable. List methods return a Page that auto-pages through Page.All.
Retrying safely ¶
The client retries 429 and 5xx responses with jittered exponential backoff, honoring Retry-After. That is safe for reads, but a retried send could go out twice — so anything that sends mail or spends money accepts an idempotency key, and repeating it replays the original response:
result, resp, err := client.Emails.Send(ctx, id, params,
warmbly.WithIdempotencyKey("order-4171-welcome"))
if resp.IdempotentReplayed {
// The original send already went out.
}
Errors ¶
Every non-2xx response decodes into an Error carrying the message, code and request id. Match it with errors.Is against the package sentinels (ErrNotFound, ErrRateLimited and the rest) rather than comparing status codes by hand.
A sentinel matches on the status alone, which several distinct refusals share. When the remedy differs, branch on the stable code instead, using the ErrCode constants and Error.HasCode:
var apiErr *warmbly.Error
if errors.As(err, &apiErr) && apiErr.HasCode(warmbly.ErrCodeStorageLimitReached) {
// Free some attachment storage; retrying will not help.
}
Reaching something new ¶
The API ships faster than this SDK. Client.Do issues a request against any path with the same authentication, retries and typed errors, and WithQueryParam adds a filter no typed parameter carries yet.
Design ¶
The module depends only on the standard library, including its own RFC 6455 websocket implementation, so it adds no transitive supply chain.
Index ¶
- Constants
- Variables
- func Bool(v bool) *bool
- func ComputeWebhookSignature(payload []byte, secret string, timestamp time.Time) string
- func Float64(v float64) *float64
- func GenerateVerifier() string
- func Int(v int) *int
- func Int64(v int64) *int64
- func S256ChallengeFromVerifier(verifier string) string
- func String(v string) *string
- func Time(v time.Time) *time.Time
- func VerifyWebhookSignature(payload []byte, signatureHeader, secret string) bool
- func VerifyWebhookSignatureAt(payload []byte, signatureHeader, secret string) (time.Time, bool)
- type ABAnalysis
- type ABTestingSettings
- type ABVariant
- type ABVariantCreateParams
- type ABVariantMetrics
- type ABVariantUpdateParams
- type AIDraft
- type AIDraftGrounding
- type AISkill
- type AIVariableParams
- type APIKey
- type APIKeyAnalytics
- type APIKeyAnalyticsParams
- type APIKeyCreateParams
- type APIKeyEndpointStat
- type APIKeyService
- func (s *APIKeyService) Analytics(ctx context.Context, id string, params *APIKeyAnalyticsParams, ...) (*APIKeyAnalytics, *Response, error)
- func (s *APIKeyService) Create(ctx context.Context, params *APIKeyCreateParams, opts ...RequestOption) (*APIKeyWithSecret, *Response, error)
- func (s *APIKeyService) Get(ctx context.Context, id string, opts ...RequestOption) (*APIKey, *Response, error)
- func (s *APIKeyService) List(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[APIKey], error)
- func (s *APIKeyService) Logs(ctx context.Context, id string, params *ListOptions, opts ...RequestOption) (*Page[APIKeyUsageLog], error)
- func (s *APIKeyService) Permissions(ctx context.Context, opts ...RequestOption) (*PermissionCatalog, *Response, error)
- func (s *APIKeyService) Revoke(ctx context.Context, id, reason string, opts ...RequestOption) (*Response, error)
- func (s *APIKeyService) RevokeSelf(ctx context.Context, reason string, opts ...RequestOption) (*Response, error)
- func (s *APIKeyService) Update(ctx context.Context, id string, params *APIKeyUpdateParams, ...) (*APIKey, *Response, error)
- func (s *APIKeyService) UsageAnalytics(ctx context.Context, params *APIKeyAnalyticsParams, opts ...RequestOption) (*APIKeyAnalytics, *Response, error)
- func (s *APIKeyService) UsageSummary(ctx context.Context, opts ...RequestOption) (*APIKeyUsageSummary, *Response, error)
- type APIKeyUpdateParams
- type APIKeyUsageBucket
- type APIKeyUsageLog
- type APIKeyUsageSummary
- type APIKeyWithSecret
- type APIUsage
- type AccountDailyUsage
- type AccountError
- type AccountHealth
- type AccountHealthTotals
- type AccountStatus
- type ActivityEvent
- type AddToCampaignConfig
- type AdvisorAction
- type AdvisorAgentResult
- type AdvisorFinding
- type AdvisorListParams
- type AdvisorPreviewChange
- type AdvisorService
- func (s *AdvisorService) AgentFix(ctx context.Context, id string, opts ...RequestOption) (*AdvisorAgentResult, *Response, error)
- func (s *AdvisorService) Apply(ctx context.Context, id string, opts ...RequestOption) (*AdvisorFinding, *Response, error)
- func (s *AdvisorService) Dismiss(ctx context.Context, id, reason string, opts ...RequestOption) (*Response, error)
- func (s *AdvisorService) Feedback(ctx context.Context, id string, helpful bool, reason string, ...) (*Response, error)
- func (s *AdvisorService) Recommendations(ctx context.Context, params *AdvisorListParams, opts ...RequestOption) ([]AdvisorFinding, *Response, error)
- func (s *AdvisorService) Refresh(ctx context.Context, opts ...RequestOption) (*AdvisorSummary, *Response, error)
- func (s *AdvisorService) Settings(ctx context.Context, opts ...RequestOption) (*AdvisorSettings, *Response, error)
- func (s *AdvisorService) Snooze(ctx context.Context, id string, days int, opts ...RequestOption) (*Response, error)
- func (s *AdvisorService) Summary(ctx context.Context, opts ...RequestOption) (*AdvisorSummary, *Response, error)
- func (s *AdvisorService) Undo(ctx context.Context, id string, opts ...RequestOption) (*AdvisorFinding, *Response, error)
- func (s *AdvisorService) UpdateSettings(ctx context.Context, settings *AdvisorSettings, opts ...RequestOption) (*AdvisorSettings, *Response, error)
- type AdvisorSettings
- type AdvisorSnippet
- type AdvisorSummary
- type AdvisorSurfaceCount
- type AdvisorUndo
- type AgentBlock
- type AgentDraft
- type AgentEvent
- type AgentSession
- type AgentSessionContext
- type AgentTool
- type AgentToolCallResult
- type AgentToolFunction
- type AgentToolFunctionSpec
- type AgentToolService
- func (s *AgentToolService) Call(ctx context.Context, name string, args any, opts ...RequestOption) (*AgentToolCallResult, *Response, error)
- func (s *AgentToolService) List(ctx context.Context, opts ...RequestOption) ([]AgentTool, *Response, error)
- func (s *AgentToolService) ListFunctions(ctx context.Context, opts ...RequestOption) ([]AgentToolFunction, *Response, error)
- type AgentTranscript
- type AgentTurn
- type AnalyticsService
- func (s *AnalyticsService) Account(ctx context.Context, id string, opts ...RequestOption) (*AccountStatus, *Response, error)
- func (s *AnalyticsService) Accounts(ctx context.Context, opts ...RequestOption) ([]AccountStatus, *Response, error)
- func (s *AnalyticsService) Campaign(ctx context.Context, id string, opts ...RequestOption) (*CampaignAnalytics, *Response, error)
- func (s *AnalyticsService) CampaignDaily(ctx context.Context, id string, from, to time.Time, opts ...RequestOption) ([]DailyStat, *Response, error)
- func (s *AnalyticsService) CampaignHourly(ctx context.Context, id string, date time.Time, opts ...RequestOption) ([]HourlyStat, *Response, error)
- func (s *AnalyticsService) CompareCampaigns(ctx context.Context, ids []string, from, to time.Time, opts ...RequestOption) (*CampaignComparison, *Response, error)
- func (s *AnalyticsService) Dashboard(ctx context.Context, period string, opts ...RequestOption) (*DashboardAnalytics, *Response, error)
- func (s *AnalyticsService) Deliverability(ctx context.Context, from, to time.Time, opts ...RequestOption) (*DeliverabilityDashboard, *Response, error)
- func (s *AnalyticsService) Usage(ctx context.Context, period string, opts ...RequestOption) (*UsageOverview, *Response, error)
- func (s *AnalyticsService) Warmup(ctx context.Context, emailID string, from, to time.Time, opts ...RequestOption) (*WarmupAnalytics, *Response, error)
- type AssistantService
- func (s *AssistantService) Approve(ctx context.Context, sessionID, decision string, fn func(*AgentEvent) bool, ...) (*Response, error)
- func (s *AssistantService) ClearSessions(ctx context.Context, opts ...RequestOption) (*Response, error)
- func (s *AssistantService) ConnectMCPServer(ctx context.Context, params *MCPServerParams, opts ...RequestOption) (*MCPServer, *Response, error)
- func (s *AssistantService) CreateSession(ctx context.Context, page, resource string, opts ...RequestOption) (*AgentSession, *Response, error)
- func (s *AssistantService) DeleteMCPServer(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *AssistantService) DeleteSession(ctx context.Context, sessionID string, opts ...RequestOption) (*Response, error)
- func (s *AssistantService) MCPServers(ctx context.Context, opts ...RequestOption) ([]MCPServer, *Response, error)
- func (s *AssistantService) RefreshMCPServer(ctx context.Context, id string, opts ...RequestOption) (*MCPServer, *Response, error)
- func (s *AssistantService) SendMessage(ctx context.Context, sessionID string, params *MessageParams, ...) (*Response, error)
- func (s *AssistantService) Sessions(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[AgentSession], error)
- func (s *AssistantService) Transcript(ctx context.Context, sessionID string, opts ...RequestOption) (*AgentTranscript, *Response, error)
- func (s *AssistantService) UpdateMCPServer(ctx context.Context, id string, params *MCPServerUpdateParams, ...) (*MCPServer, *Response, error)
- type AuditActor
- type AuditLog
- type AuditLogListParams
- type AuditLogService
- type AuthCodeOption
- type AuthConfig
- type AuthProvider
- type AuthProviders
- type AuthService
- func (s *AuthService) ApproveCLIAuth(ctx context.Context, userCode, organizationID string, opts ...RequestOption) (*CLIAuthRequest, *Response, error)
- func (s *AuthService) BeginPasskeyLogin(ctx context.Context, opts ...RequestOption) (*PasskeyLoginChallenge, *Response, error)
- func (s *AuthService) BeginPasskeyRegistration(ctx context.Context, opts ...RequestOption) (json.RawMessage, *Response, error)
- func (s *AuthService) BeginSSO(ctx context.Context, provider string, opts ...RequestOption) (*SSORedirect, *Response, error)
- func (s *AuthService) CLIAuthRequest(ctx context.Context, userCode string, opts ...RequestOption) (*CLIAuthRequest, *Response, error)
- func (s *AuthService) CancelDeletion(ctx context.Context, reason string, opts ...RequestOption) (*Response, error)
- func (s *AuthService) ChangePassword(ctx context.Context, currentPassword, newPassword string, ...) (*Response, error)
- func (s *AuthService) CompleteOnboarding(ctx context.Context, params *OnboardingParams, opts ...RequestOption) (*User, *Response, error)
- func (s *AuthService) Config(ctx context.Context, opts ...RequestOption) (*AuthConfig, *Response, error)
- func (s *AuthService) ConfirmTwoFA(ctx context.Context, code string, opts ...RequestOption) (*TwoFARecoveryCodes, *Response, error)
- func (s *AuthService) DangerZone(ctx context.Context, opts ...RequestOption) (*DangerZoneStatus, *Response, error)
- func (s *AuthService) DeleteAvatar(ctx context.Context, opts ...RequestOption) (*Response, error)
- func (s *AuthService) DeleteDeviceToken(ctx context.Context, token string, opts ...RequestOption) (*Response, error)
- func (s *AuthService) DeletePasskey(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *AuthService) DenyCLIAuth(ctx context.Context, userCode string, opts ...RequestOption) (*Response, error)
- func (s *AuthService) DisableTwoFA(ctx context.Context, code string, opts ...RequestOption) (*Response, error)
- func (s *AuthService) EnrollTwoFA(ctx context.Context, opts ...RequestOption) (*TwoFAEnrollment, *Response, error)
- func (s *AuthService) ExchangeSSO(ctx context.Context, code, binding string, opts ...RequestOption) (*Session, *Response, error)
- func (s *AuthService) FinishPasskeyLogin(ctx context.Context, session string, assertion json.RawMessage, ...) (*Session, *Response, error)
- func (s *AuthService) FinishPasskeyRegistration(ctx context.Context, name string, attestation json.RawMessage, ...) (*PasskeyCredential, *Response, error)
- func (s *AuthService) Instance(ctx context.Context, opts ...RequestOption) (*InstanceInfo, *Response, error)
- func (s *AuthService) Login(ctx context.Context, params *LoginParams, opts ...RequestOption) (*AuthStep, *Response, error)
- func (s *AuthService) LoginConfirm(ctx context.Context, params *ConfirmParams, opts ...RequestOption) (*Session, *Response, error)
- func (s *AuthService) LoginWithApple(ctx context.Context, identityToken string, opts ...RequestOption) (*Session, *Response, error)
- func (s *AuthService) LoginWithGoogle(ctx context.Context, idToken string, opts ...RequestOption) (*Session, *Response, error)
- func (s *AuthService) Logout(ctx context.Context, opts ...RequestOption) (*Response, error)
- func (s *AuthService) LogoutAll(ctx context.Context, opts ...RequestOption) (*Response, error)
- func (s *AuthService) MarkAllNotificationsRead(ctx context.Context, opts ...RequestOption) (*Response, error)
- func (s *AuthService) MarkNotificationRead(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *AuthService) Me(ctx context.Context, opts ...RequestOption) (*User, *Response, error)
- func (s *AuthService) NotificationPreferences(ctx context.Context, opts ...RequestOption) (*NotificationPreferencesResult, *Response, error)
- func (s *AuthService) Notifications(ctx context.Context, opts ...RequestOption) (*NotificationFeed, *Response, error)
- func (s *AuthService) Passkeys(ctx context.Context, opts ...RequestOption) ([]PasskeyCredential, *Response, error)
- func (s *AuthService) PollCLIAuth(ctx context.Context, deviceCode string, opts ...RequestOption) (*CLIAuthPoll, *Response, error)
- func (s *AuthService) Providers(ctx context.Context, opts ...RequestOption) (*AuthProviders, *Response, error)
- func (s *AuthService) Refresh(ctx context.Context, refreshToken string, opts ...RequestOption) (*Session, *Response, error)
- func (s *AuthService) Register(ctx context.Context, params *LoginParams, opts ...RequestOption) (*AuthStep, *Response, error)
- func (s *AuthService) RegisterConfirm(ctx context.Context, params *ConfirmParams, opts ...RequestOption) (*AuthStep, *Response, error)
- func (s *AuthService) RegisterDeviceToken(ctx context.Context, token, platform, environment string, ...) (*Response, error)
- func (s *AuthService) RenamePasskey(ctx context.Context, id, name string, opts ...RequestOption) (*PasskeyCredential, *Response, error)
- func (s *AuthService) ResetPassword(ctx context.Context, email, turnstile string, opts ...RequestOption) (*Response, error)
- func (s *AuthService) ResetPasswordConfirm(ctx context.Context, session, password, turnstile string, ...) (*Response, error)
- func (s *AuthService) RevokeOtherSessions(ctx context.Context, opts ...RequestOption) (*Response, error)
- func (s *AuthService) RevokeSession(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *AuthService) ScheduleDeletion(ctx context.Context, params *ScheduleDeletionParams, opts ...RequestOption) (*ScheduledDeletion, *Response, error)
- func (s *AuthService) Sessions(ctx context.Context, opts ...RequestOption) ([]UserSession, *Response, error)
- func (s *AuthService) SetUndoSendSeconds(ctx context.Context, seconds int, opts ...RequestOption) (*Response, error)
- func (s *AuthService) Setup(ctx context.Context, params *SetupParams, opts ...RequestOption) (*Session, *Response, error)
- func (s *AuthService) StartCLIAuth(ctx context.Context, params *CLIAuthStartParams, opts ...RequestOption) (*CLIAuthHandshake, *Response, error)
- func (s *AuthService) TwoFAStatus(ctx context.Context, opts ...RequestOption) (*TwoFAStatus, *Response, error)
- func (s *AuthService) UpdateNotificationPreferences(ctx context.Context, prefs *NotificationPreferences, opts ...RequestOption) (*NotificationPreferencesResult, *Response, error)
- func (s *AuthService) UpdateProfile(ctx context.Context, params *ProfileUpdateParams, opts ...RequestOption) (*User, *Response, error)
- func (s *AuthService) UploadAvatar(ctx context.Context, file *FileUpload, opts ...RequestOption) (string, *Response, error)
- func (s *AuthService) VerifyTwoFA(ctx context.Context, pendingToken, code string, opts ...RequestOption) (*Session, *Response, error)
- func (s *AuthService) WaitForCLIAuth(ctx context.Context, hs *CLIAuthHandshake, opts ...RequestOption) (*CLIAuthPoll, error)
- type AuthStep
- type Authenticator
- type AuthenticatorFunc
- type AuthorizeParams
- type AuthorizedApp
- type Automation
- type AutomationCondition
- type AutomationCreateParams
- type AutomationEdge
- type AutomationGraph
- type AutomationNode
- type AutomationNodeResult
- type AutomationRun
- type AutomationService
- func (s *AutomationService) Create(ctx context.Context, params *AutomationCreateParams, opts ...RequestOption) (*Automation, *Response, error)
- func (s *AutomationService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *AutomationService) DryRun(ctx context.Context, id string, params *AutomationTestParams, ...) (*AutomationTestResult, *Response, error)
- func (s *AutomationService) Get(ctx context.Context, id string, opts ...RequestOption) (*Automation, *Response, error)
- func (s *AutomationService) List(ctx context.Context, opts ...RequestOption) ([]Automation, *Response, error)
- func (s *AutomationService) Runs(ctx context.Context, id string, limit int, opts ...RequestOption) ([]AutomationRun, *Response, error)
- func (s *AutomationService) Test(ctx context.Context, id string, data any, opts ...RequestOption) (*AutomationTestResult, *Response, error)
- func (s *AutomationService) Update(ctx context.Context, id string, params *AutomationUpdateParams, ...) (*Automation, *Response, error)
- func (s *AutomationService) UpdateLayout(ctx context.Context, id string, positions []NodePosition, ...) (*Response, error)
- type AutomationTestParams
- type AutomationTestResult
- type AutomationUpdateParams
- type BillingService
- func (s *BillingService) AppliedDiscounts(ctx context.Context, opts ...RequestOption) ([]DiscountRedemption, *Response, error)
- func (s *BillingService) BuyCredits(ctx context.Context, pack, successURL, cancelURL string, opts ...RequestOption) (*CheckoutSession, *Response, error)
- func (s *BillingService) Cancel(ctx context.Context, atPeriodEnd bool, opts ...RequestOption) (*Response, error)
- func (s *BillingService) ChangePlan(ctx context.Context, params *ChangePlanParams, opts ...RequestOption) (*Subscription, *Response, error)
- func (s *BillingService) Checkout(ctx context.Context, params *CheckoutParams, opts ...RequestOption) (*CheckoutSession, *Response, error)
- func (s *BillingService) CreditSettings(ctx context.Context, opts ...RequestOption) (*CreditSettings, *Response, error)
- func (s *BillingService) CreditTransactions(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[CreditTransaction], error)
- func (s *BillingService) CreditUsage(ctx context.Context, days int, opts ...RequestOption) (*CreditUsage, *Response, error)
- func (s *BillingService) Credits(ctx context.Context, opts ...RequestOption) (*CreditBalance, *Response, error)
- func (s *BillingService) EnsureReferralCode(ctx context.Context, opts ...RequestOption) (*ReferralCode, *Response, error)
- func (s *BillingService) EnterpriseInquiry(ctx context.Context, params *EnterpriseInquiryParams, opts ...RequestOption) (string, *Response, error)
- func (s *BillingService) Features(ctx context.Context, opts ...RequestOption) (*FeatureStatus, *Response, error)
- func (s *BillingService) Get(ctx context.Context, opts ...RequestOption) (*Subscription, *Response, error)
- func (s *BillingService) Limits(ctx context.Context, opts ...RequestOption) (*SubscriptionWithLimits, *Response, error)
- func (s *BillingService) Portal(ctx context.Context, returnURL string, opts ...RequestOption) (string, *Response, error)
- func (s *BillingService) PreviewPlanChange(ctx context.Context, newPlanID string, opts ...RequestOption) (*PlanChangePreview, *Response, error)
- func (s *BillingService) Referral(ctx context.Context, opts ...RequestOption) (*ReferralSummary, *Response, error)
- func (s *BillingService) ReferralAttributions(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[ReferralAttribution], error)
- func (s *BillingService) ReferralEarnings(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[ReferralEarning], error)
- func (s *BillingService) Trial(ctx context.Context, opts ...RequestOption) (*TrialStatus, *Response, error)
- func (s *BillingService) UpdateCreditSettings(ctx context.Context, params *CreditSettingsParams, opts ...RequestOption) (*CreditSettings, *Response, error)
- func (s *BillingService) ValidateDiscount(ctx context.Context, code, planID string, opts ...RequestOption) (*DiscountPreview, *Response, error)
- type BouncePipelineSettings
- type BulkTagParams
- type BulkTagResult
- type CLIAuthHandshake
- type CLIAuthPoll
- type CLIAuthRequest
- type CLIAuthStartParams
- type CRMService
- func (s *CRMService) CreateDeal(ctx context.Context, params *DealCreateParams, opts ...RequestOption) (*Deal, *Response, error)
- func (s *CRMService) CreatePipeline(ctx context.Context, params *PipelineCreateParams, opts ...RequestOption) (*Pipeline, *Response, error)
- func (s *CRMService) CreateStage(ctx context.Context, pipelineID string, params *StageCreateParams, ...) (*PipelineStage, *Response, error)
- func (s *CRMService) CreateTask(ctx context.Context, params *CRMTaskCreateParams, opts ...RequestOption) (*CRMTask, *Response, error)
- func (s *CRMService) CreateTaskType(ctx context.Context, params *TaskTypeCreateParams, opts ...RequestOption) (*CRMTaskType, *Response, error)
- func (s *CRMService) DealsSummary(ctx context.Context, params *DealSearchParams, opts ...RequestOption) (*DealsSummary, *Response, error)
- func (s *CRMService) DeleteDeal(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *CRMService) DeletePipeline(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *CRMService) DeleteStage(ctx context.Context, pipelineID, stageID string, opts ...RequestOption) (*Response, error)
- func (s *CRMService) DeleteTask(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *CRMService) DeleteTaskType(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *CRMService) GetDeal(ctx context.Context, id string, opts ...RequestOption) (*Deal, *Response, error)
- func (s *CRMService) GetPipeline(ctx context.Context, id string, opts ...RequestOption) (*Pipeline, *Response, error)
- func (s *CRMService) GetTask(ctx context.Context, id string, opts ...RequestOption) (*CRMTask, *Response, error)
- func (s *CRMService) ListDeals(ctx context.Context, params *DealListParams, opts ...RequestOption) (*Page[Deal], error)
- func (s *CRMService) ListPipelines(ctx context.Context, opts ...RequestOption) ([]Pipeline, *Response, error)
- func (s *CRMService) ListTaskTypes(ctx context.Context, opts ...RequestOption) ([]CRMTaskType, *Response, error)
- func (s *CRMService) ListTasks(ctx context.Context, params *CRMTaskListParams, opts ...RequestOption) (*Page[CRMTask], error)
- func (s *CRMService) SearchDeals(ctx context.Context, params *DealSearchParams, opts ...RequestOption) (*Page[Deal], error)
- func (s *CRMService) SearchTasks(ctx context.Context, params *TaskSearchParams, opts ...RequestOption) (*Page[CRMTask], error)
- func (s *CRMService) TasksSummary(ctx context.Context, params *TaskSearchParams, opts ...RequestOption) (*TasksSummary, *Response, error)
- func (s *CRMService) UpdateDeal(ctx context.Context, id string, params *DealUpdateParams, ...) (*Deal, *Response, error)
- func (s *CRMService) UpdatePipeline(ctx context.Context, id string, params *PipelineUpdateParams, ...) (*Pipeline, *Response, error)
- func (s *CRMService) UpdateStage(ctx context.Context, pipelineID, stageID string, params *StageUpdateParams, ...) (*PipelineStage, *Response, error)
- func (s *CRMService) UpdateTask(ctx context.Context, id string, params *CRMTaskUpdateParams, ...) (*CRMTask, *Response, error)
- func (s *CRMService) UpdateTaskType(ctx context.Context, id string, params *TaskTypeUpdateParams, ...) (*CRMTaskType, *Response, error)
- type CRMTask
- type CRMTaskCreateParams
- type CRMTaskListParams
- type CRMTaskType
- type CRMTaskUpdateParams
- type Campaign
- type CampaignAdvancedSettings
- type CampaignAnalytics
- type CampaignAnalyticsTotals
- type CampaignAttachment
- type CampaignComparison
- type CampaignCreateParams
- type CampaignDuplicateParams
- type CampaignEngagement
- type CampaignEstimateParams
- type CampaignEstimateResult
- type CampaignFolderCount
- type CampaignFormStats
- type CampaignLeadCounts
- type CampaignListParams
- type CampaignLogEntry
- type CampaignSegmentLink
- type CampaignSegmentsResult
- type CampaignSender
- type CampaignSenderInput
- type CampaignService
- func (s *CampaignService) ABAnalysis(ctx context.Context, id string, opts ...RequestOption) (*ABAnalysis, *Response, error)
- func (s *CampaignService) AdvancedSettings(ctx context.Context, id string, opts ...RequestOption) (*CampaignAdvancedSettings, *Response, error)
- func (s *CampaignService) Create(ctx context.Context, params *CampaignCreateParams, opts ...RequestOption) (*Campaign, *Response, error)
- func (s *CampaignService) CreateABVariant(ctx context.Context, id string, params *ABVariantCreateParams, ...) (*ABVariant, *Response, error)
- func (s *CampaignService) CreateStep(ctx context.Context, id string, opts ...RequestOption) (*Step, *Response, error)
- func (s *CampaignService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *CampaignService) DeleteABVariant(ctx context.Context, id, variantID string, opts ...RequestOption) (*Response, error)
- func (s *CampaignService) DeleteAttachment(ctx context.Context, id, attachmentID string, opts ...RequestOption) (*Response, error)
- func (s *CampaignService) DeleteStep(ctx context.Context, id, stepID string, opts ...RequestOption) (*Response, error)
- func (s *CampaignService) Duplicate(ctx context.Context, id string, params *CampaignDuplicateParams, ...) (*Campaign, *Response, error)
- func (s *CampaignService) Estimate(ctx context.Context, params *CampaignEstimateParams, opts ...RequestOption) (*CampaignEstimateResult, *Response, error)
- func (s *CampaignService) Forms(ctx context.Context, id string, opts ...RequestOption) ([]CampaignFormStats, *Response, error)
- func (s *CampaignService) Get(ctx context.Context, id string, opts ...RequestOption) (*Campaign, *Response, error)
- func (s *CampaignService) List(ctx context.Context, params *CampaignListParams, opts ...RequestOption) (*Page[Campaign], error)
- func (s *CampaignService) ListABVariants(ctx context.Context, id string, opts ...RequestOption) ([]ABVariant, *Response, error)
- func (s *CampaignService) ListAttachments(ctx context.Context, id string, opts ...RequestOption) ([]CampaignAttachment, *Response, error)
- func (s *CampaignService) ListSegments(ctx context.Context, id string, opts ...RequestOption) ([]CampaignSegmentLink, *Response, error)
- func (s *CampaignService) ListSteps(ctx context.Context, id string, opts ...RequestOption) ([]Step, *Response, error)
- func (s *CampaignService) Logs(ctx context.Context, id string, params *ListOptions, opts ...RequestOption) (*Page[CampaignLogEntry], error)
- func (s *CampaignService) Overview(ctx context.Context, opts ...RequestOption) (*CampaignsOverview, *Response, error)
- func (s *CampaignService) Preflight(ctx context.Context, id string, opts ...RequestOption) (*PreflightResult, *Response, error)
- func (s *CampaignService) PreviewTemplate(ctx context.Context, params *TemplatePreviewParams, opts ...RequestOption) (*TemplatePreviewResult, *Response, error)
- func (s *CampaignService) ReplaceSenders(ctx context.Context, id string, senders []CampaignSenderInput, ...) ([]CampaignSender, *Response, error)
- func (s *CampaignService) SendTestEmail(ctx context.Context, id string, params *TestEmailParams, opts ...RequestOption) (*TestEmailResult, *Response, error)
- func (s *CampaignService) Senders(ctx context.Context, id string, opts ...RequestOption) ([]CampaignSender, *Response, error)
- func (s *CampaignService) SetSegments(ctx context.Context, id string, segmentIDs []string, opts ...RequestOption) (*CampaignSegmentsResult, *Response, error)
- func (s *CampaignService) Start(ctx context.Context, id string, opts ...RequestOption) (*CampaignStatusChange, *Response, error)
- func (s *CampaignService) StartWithOptions(ctx context.Context, id string, params *CampaignStartParams, ...) (*CampaignStatusChange, *Response, error)
- func (s *CampaignService) Stop(ctx context.Context, id string, opts ...RequestOption) (*CampaignStatusChange, *Response, error)
- func (s *CampaignService) Update(ctx context.Context, id string, params *CampaignUpdateParams, ...) (*Campaign, *Response, error)
- func (s *CampaignService) UpdateABVariant(ctx context.Context, id, variantID string, params *ABVariantUpdateParams, ...) (*ABVariant, *Response, error)
- func (s *CampaignService) UpdateAdvancedSettings(ctx context.Context, id string, overrides *OutreachSettings, ...) (*Response, error)
- func (s *CampaignService) UpdateStep(ctx context.Context, id, stepID string, params *StepUpdateParams, ...) (*Step, *Response, error)
- func (s *CampaignService) UpdateStepLayout(ctx context.Context, id string, positions []StepPosition, ...) (*Response, error)
- func (s *CampaignService) UploadAttachment(ctx context.Context, id string, file *FileUpload, stepID string, ...) (*CampaignAttachment, *Response, error)
- func (s *CampaignService) VerifyTrackingDomain(ctx context.Context, id string, opts ...RequestOption) (*TrackingDomainStatus, *Response, error)
- type CampaignStartParams
- type CampaignStatusChange
- type CampaignSummary
- type CampaignUpdateParams
- type CampaignUsage
- type CampaignsOverview
- type CategoryPref
- type ChangePlanParams
- type ChannelPrefs
- type CheckoutParams
- type CheckoutSession
- type Client
- type ClientCredentialsConfig
- type CloudLinkConnectPollResult
- type CloudLinkConnection
- type CloudLinkMailbox
- type CloudLinkOAuthStart
- type CloudLinkPendingConnect
- type CloudLinkService
- func (s *CloudLinkService) AdoptWorkspaceMailbox(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
- func (s *CloudLinkService) Connect(ctx context.Context, cloudURL string, opts ...RequestOption) (*CloudLinkPendingConnect, *Response, error)
- func (s *CloudLinkService) Disconnect(ctx context.Context, opts ...RequestOption) (*Response, error)
- func (s *CloudLinkService) EnrollMailbox(ctx context.Context, id string, opts ...RequestOption) (*CloudLinkMailbox, *Response, error)
- func (s *CloudLinkService) FinishOAuth(ctx context.Context, session string, opts ...RequestOption) (*Email, *Response, error)
- func (s *CloudLinkService) ListMailboxes(ctx context.Context, opts ...RequestOption) ([]CloudLinkMailbox, *Response, error)
- func (s *CloudLinkService) ListWorkspaceMailboxes(ctx context.Context, opts ...RequestOption) ([]PoolLinkWorkspaceMailbox, *Response, error)
- func (s *CloudLinkService) PauseMailbox(ctx context.Context, id string, opts ...RequestOption) (*CloudLinkMailbox, *Response, error)
- func (s *CloudLinkService) PollConnect(ctx context.Context, opts ...RequestOption) (*CloudLinkConnectPollResult, *Response, error)
- func (s *CloudLinkService) ResumeMailbox(ctx context.Context, id string, opts ...RequestOption) (*CloudLinkMailbox, *Response, error)
- func (s *CloudLinkService) StartOAuth(ctx context.Context, provider string, opts ...RequestOption) (*CloudLinkOAuthStart, *Response, error)
- func (s *CloudLinkService) Status(ctx context.Context, opts ...RequestOption) (*CloudLinkStatus, *Response, error)
- func (s *CloudLinkService) UnenrollMailbox(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *CloudLinkService) WaitForConnect(ctx context.Context, pending *CloudLinkPendingConnect, opts ...RequestOption) (*CloudLinkConnectPollResult, error)
- type CloudLinkStatus
- type ColdRamp
- type ComposeCandidate
- type ComposeCandidates
- type ComposeDraft
- type ComposeDraftParams
- type ComposeResult
- type ComposeSuppression
- type ConfirmParams
- type ConnectParams
- type ConnectionConfigParams
- type ConnectionDetail
- type ConnectionWebhookSecret
- type ConsentInfo
- type Contact
- type ContactActivity
- type ContactBulkUpdateParams
- type ContactCampaignProgress
- type ContactCampaignState
- type ContactCampaignStep
- type ContactCategoryCount
- type ContactCreatedPayload
- type ContactDetail
- type ContactEngagement
- type ContactExportParams
- type ContactFieldEdit
- type ContactFieldFilter
- type ContactImportParams
- type ContactImportPreview
- type ContactImportQuality
- type ContactImportResult
- type ContactInput
- type ContactLinkClick
- type ContactNextAction
- type ContactNote
- type ContactPage
- type ContactPageHit
- type ContactSearchParams
- type ContactSegmentMembership
- type ContactSentEmail
- type ContactService
- func (s *ContactService) Activities(ctx context.Context, id string, params *ListOptions, opts ...RequestOption) (*Page[ContactActivity], error)
- func (s *ContactService) AddNote(ctx context.Context, id, content string, opts ...RequestOption) (*ContactNote, *Response, error)
- func (s *ContactService) BatchResearch(ctx context.Context, contactIDs []string, objective string, ...) (int, *Response, error)
- func (s *ContactService) BulkDelete(ctx context.Context, ids []string, opts ...RequestOption) (*Response, error)
- func (s *ContactService) BulkUpdate(ctx context.Context, params *ContactBulkUpdateParams, opts ...RequestOption) ([]Contact, *Response, error)
- func (s *ContactService) CampaignStates(ctx context.Context, id string, opts ...RequestOption) ([]ContactCampaignState, *Response, error)
- func (s *ContactService) Create(ctx context.Context, contacts []ContactInput, opts ...RequestOption) ([]Contact, *Response, error)
- func (s *ContactService) CustomFields(ctx context.Context, opts ...RequestOption) ([]string, *Response, error)
- func (s *ContactService) Deals(ctx context.Context, id string, opts ...RequestOption) ([]Deal, *Response, error)
- func (s *ContactService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *ContactService) DeleteNote(ctx context.Context, id, noteID string, opts ...RequestOption) (*Response, error)
- func (s *ContactService) Emails(ctx context.Context, id string, opts ...RequestOption) ([]ContactSentEmail, *Response, error)
- func (s *ContactService) Export(ctx context.Context, params *ContactExportParams, w io.Writer, ...) (*Response, error)
- func (s *ContactService) Get(ctx context.Context, id string, opts ...RequestOption) (*ContactDetail, *Response, error)
- func (s *ContactService) ImportCommit(ctx context.Context, file *FileUpload, params *ContactImportParams, ...) (*ContactImportResult, *Response, error)
- func (s *ContactService) ImportPreview(ctx context.Context, file *FileUpload, opts ...RequestOption) (*ContactImportPreview, *Response, error)
- func (s *ContactService) ListResearch(ctx context.Context, id string, limit int, opts ...RequestOption) ([]ResearchRun, *Response, error)
- func (s *ContactService) ListTimeline(ctx context.Context, id string, params *TimelineParams, opts ...RequestOption) (*Page[TimelineEvent], error)
- func (s *ContactService) Lookup(ctx context.Context, email string, opts ...RequestOption) (*ContactDetail, *Response, error)
- func (s *ContactService) Notes(ctx context.Context, id string, params *ListOptions, opts ...RequestOption) (*Page[ContactNote], error)
- func (s *ContactService) RequestVerification(ctx context.Context, params *ContactVerificationParams, opts ...RequestOption) (*ContactVerificationResult, *Response, error)
- func (s *ContactService) Research(ctx context.Context, id, objective string, opts ...RequestOption) (*ResearchRun, *Response, error)
- func (s *ContactService) Search(ctx context.Context, params *ContactSearchParams, opts ...RequestOption) (*ContactPage, error)
- func (s *ContactService) Segments(ctx context.Context, id string, opts ...RequestOption) ([]ContactSegmentMembership, *Response, error)
- func (s *ContactService) Timeline(ctx context.Context, id string, opts ...RequestOption) ([]TimelineEvent, *Response, error)
- func (s *ContactService) Update(ctx context.Context, id string, params *ContactUpdateParams, ...) (*Contact, *Response, error)
- func (s *ContactService) UpdateNote(ctx context.Context, id, noteID, content string, opts ...RequestOption) (*ContactNote, *Response, error)
- func (s *ContactService) VerificationOverview(ctx context.Context, opts ...RequestOption) (*ContactVerificationOverview, *Response, error)
- type ContactSuppression
- type ContactUpdateParams
- type ContactUsage
- type ContactVerificationCounts
- type ContactVerificationDetail
- type ContactVerificationEvidence
- type ContactVerificationOverview
- type ContactVerificationParams
- type ContactVerificationResult
- type ContactsCounts
- type CreditBalance
- type CreditContext
- type CreditPack
- type CreditSettings
- type CreditSettingsParams
- type CreditTransaction
- type CreditUsage
- type CreditUsageBucket
- type CreditUsagePoint
- type DailyPlan
- type DailyStat
- type DangerZoneStatus
- type DashboardAnalytics
- type DateRange
- type DeadLetter
- type DeadLetterListParams
- type Deal
- type DealCreateParams
- type DealListParams
- type DealSearchParams
- type DealStageSummary
- type DealUpdateParams
- type DealsSummary
- type DeliverabilityBreakdown
- type DeliverabilityDashboard
- type DeliverabilityDashboardSettings
- type DeliverabilityDay
- type DeliverabilityEventParams
- type DeliverabilityService
- type DiscountPreview
- type DiscountRedemption
- type DomainAuthCheck
- type DynamicClient
- type DynamicClientParams
- type EditParams
- type Email
- type EmailAccountUsage
- type EmailListParams
- type EmailService
- func (s *EmailService) Allowance(ctx context.Context, opts ...RequestOption) (*MailboxAllowance, *Response, error)
- func (s *EmailService) AppealWarmupBan(ctx context.Context, id string, params *WarmupAppealParams, ...) (*WarmupAppealResult, *Response, error)
- func (s *EmailService) AuthCheck(ctx context.Context, id string, opts ...RequestOption) (*DomainAuthCheck, *Response, error)
- func (s *EmailService) Behavior(ctx context.Context, id string, opts ...RequestOption) (*SendingBehavior, *Response, error)
- func (s *EmailService) BehaviorPlan(ctx context.Context, id string, opts ...RequestOption) (*DailyPlan, *Response, error)
- func (s *EmailService) BulkTag(ctx context.Context, params *BulkTagParams, opts ...RequestOption) (*BulkTagResult, *Response, error)
- func (s *EmailService) ConnectSMTPIMAP(ctx context.Context, params *SMTPIMAPParams, opts ...RequestOption) (*Email, *Response, error)
- func (s *EmailService) ConnectSMTPIMAPBulk(ctx context.Context, params *SMTPIMAPBulkParams, opts ...RequestOption) (*MailboxBulkResult, *Response, error)
- func (s *EmailService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *EmailService) FinishOAuth(ctx context.Context, code, state string, opts ...RequestOption) (*Email, *Response, error)
- func (s *EmailService) Get(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
- func (s *EmailService) GetTrackingDomain(ctx context.Context, id string, opts ...RequestOption) (*TrackingDomainStatus, *Response, error)
- func (s *EmailService) Hold(ctx context.Context, id string, opts ...RequestOption) (*SendLifecycleState, *Response, error)
- func (s *EmailService) List(ctx context.Context, params *EmailListParams, opts ...RequestOption) (*Page[Email], error)
- func (s *EmailService) PauseWarmup(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
- func (s *EmailService) ReauthOAuth(ctx context.Context, id string, opts ...RequestOption) (*OAuthStartResult, *Response, error)
- func (s *EmailService) RefreshAuthCheck(ctx context.Context, id string, opts ...RequestOption) (*DomainAuthCheck, *Response, error)
- func (s *EmailService) Release(ctx context.Context, id string, opts ...RequestOption) (*SendLifecycleState, *Response, error)
- func (s *EmailService) ResumeWarmup(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
- func (s *EmailService) Send(ctx context.Context, id string, params *SendEmailParams, opts ...RequestOption) (*SendResult, *Response, error)
- func (s *EmailService) StartOAuth(ctx context.Context, provider string, opts ...RequestOption) (*OAuthStartResult, *Response, error)
- func (s *EmailService) StartWarmup(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
- func (s *EmailService) StopWarmup(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
- func (s *EmailService) SyncStatus(ctx context.Context, id string, opts ...RequestOption) (*MailboxSync, *Response, error)
- func (s *EmailService) Update(ctx context.Context, id string, params *EmailUpdateParams, ...) (*Email, *Response, error)
- func (s *EmailService) UpdateBehavior(ctx context.Context, id string, params *SendingBehaviorUpdateParams, ...) (*SendingBehavior, *Response, error)
- func (s *EmailService) UpdateSMTPIMAPCredentials(ctx context.Context, id string, params *SMTPIMAPCredentialsParams, ...) (*Email, *Response, error)
- func (s *EmailService) UpdateTrackingDomain(ctx context.Context, id, domain string, opts ...RequestOption) (*TrackingDomainStatus, *Response, error)
- func (s *EmailService) Verify(ctx context.Context, email string, opts ...RequestOption) (*VerifyResult, *Response, error)
- func (s *EmailService) VerifyTrackingDomain(ctx context.Context, id string, opts ...RequestOption) (*TrackingDomainStatus, *Response, error)
- func (s *EmailService) WarmupBanStatus(ctx context.Context, id string, opts ...RequestOption) (*WarmupBanStatus, *Response, error)
- type EmailUpdateParams
- type EngagementBucket
- type EngagementOrigin
- type EnterpriseInquiryParams
- type Error
- type EventSubscription
- type EventSubscriptionParams
- type FeatureStatus
- type FieldMapping
- type FieldMappingInput
- type FileUpload
- type Form
- type FormCreateParams
- type FormDesign
- type FormField
- type FormFunnelPage
- type FormIdentifiedVisitor
- type FormLink
- type FormService
- func (s *FormService) Config(ctx context.Context, opts ...RequestOption) (*FormsConfig, *Response, error)
- func (s *FormService) Create(ctx context.Context, params *FormCreateParams, opts ...RequestOption) (*Form, *Response, error)
- func (s *FormService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *FormService) DeleteAsset(ctx context.Context, id, kind string, opts ...RequestOption) (*Form, *Response, error)
- func (s *FormService) DeleteSubmission(ctx context.Context, id, submissionID string, opts ...RequestOption) (*Response, error)
- func (s *FormService) Domain(ctx context.Context, opts ...RequestOption) (*FormsDomainStatus, *Response, error)
- func (s *FormService) Get(ctx context.Context, id string, opts ...RequestOption) (*Form, *Response, error)
- func (s *FormService) List(ctx context.Context, opts ...RequestOption) ([]Form, *Response, error)
- func (s *FormService) ListSubmissions(ctx context.Context, id string, params *FormSubmissionListParams, ...) (*Page[FormSubmission], error)
- func (s *FormService) MintLink(ctx context.Context, id, contactID string, opts ...RequestOption) (*FormLink, *Response, error)
- func (s *FormService) SetDomain(ctx context.Context, domain string, opts ...RequestOption) (*FormsDomainStatus, *Response, error)
- func (s *FormService) Stats(ctx context.Context, id, window string, opts ...RequestOption) (*FormStats, *Response, error)
- func (s *FormService) Update(ctx context.Context, id string, params *FormUpdateParams, ...) (*Form, *Response, error)
- func (s *FormService) UploadAsset(ctx context.Context, id, kind string, file *FileUpload, opts ...RequestOption) (*Form, *Response, error)
- func (s *FormService) VerifyDomain(ctx context.Context, opts ...RequestOption) (*FormsDomainStatus, *Response, error)
- type FormStats
- type FormStatsBucket
- type FormStatsDay
- type FormStatsTotals
- type FormSubmission
- type FormSubmissionListParams
- type FormSubmittedPayload
- type FormUpdateParams
- type FormsConfig
- type FormsDomainStatus
- type GatewayTicket
- type Generation
- type GenerationService
- func (s *GenerationService) AIVariable(ctx context.Context, params *AIVariableParams, opts ...RequestOption) (*Generation, *Response, error)
- func (s *GenerationService) Edit(ctx context.Context, params *EditParams, opts ...RequestOption) (*Generation, *Response, error)
- func (s *GenerationService) Write(ctx context.Context, params *WriteParams, opts ...RequestOption) (*Generation, *Response, error)
- type Group
- type GroupCreateParams
- type GroupOrder
- type GroupService
- func (s *GroupService) Create(ctx context.Context, params *GroupCreateParams, opts ...RequestOption) (*Group, *Response, error)
- func (s *GroupService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *GroupService) Move(ctx context.Context, id string, position int32, opts ...RequestOption) ([]GroupOrder, *Response, error)
- func (s *GroupService) Update(ctx context.Context, id string, params *GroupUpdateParams, ...) (*Group, *Response, error)
- type GroupUpdateParams
- type HourlyStat
- type Identity
- type ImportColumnMapping
- type ImportRowError
- type InstanceInfo
- type InstanceRelease
- type IntegrationCatalogEntry
- type IntegrationConnection
- type IntegrationService
- func (s *IntegrationService) Bookings(ctx context.Context, opts ...RequestOption) ([]Meeting, *Response, error)
- func (s *IntegrationService) Catalog(ctx context.Context, opts ...RequestOption) ([]IntegrationCatalogEntry, *Response, error)
- func (s *IntegrationService) Connect(ctx context.Context, params *ConnectParams, opts ...RequestOption) (*IntegrationConnection, *Response, error)
- func (s *IntegrationService) Connection(ctx context.Context, id string, opts ...RequestOption) (*ConnectionDetail, *Response, error)
- func (s *IntegrationService) Connections(ctx context.Context, opts ...RequestOption) ([]IntegrationConnection, *Response, error)
- func (s *IntegrationService) CreateEvent(ctx context.Context, id string, params *EventSubscriptionParams, ...) (*EventSubscription, *Response, error)
- func (s *IntegrationService) DeleteEvent(ctx context.Context, id, eventID string, opts ...RequestOption) (*Response, error)
- func (s *IntegrationService) Disconnect(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *IntegrationService) Events(ctx context.Context, id string, opts ...RequestOption) ([]EventSubscription, *Response, error)
- func (s *IntegrationService) FieldMappings(ctx context.Context, id string, opts ...RequestOption) ([]FieldMapping, *Response, error)
- func (s *IntegrationService) FinishOAuth(ctx context.Context, code, state string, opts ...RequestOption) (*IntegrationConnection, *Response, error)
- func (s *IntegrationService) Push(ctx context.Context, id string, contactIDs []string, opts ...RequestOption) (*PushResult, *Response, error)
- func (s *IntegrationService) ReauthOAuth(ctx context.Context, id string, opts ...RequestOption) (*OAuthStartResult, *Response, error)
- func (s *IntegrationService) ReplaceFieldMappings(ctx context.Context, id, object string, mappings []FieldMappingInput, ...) ([]FieldMapping, *Response, error)
- func (s *IntegrationService) Runs(ctx context.Context, id string, opts ...RequestOption) ([]SyncRun, *Response, error)
- func (s *IntegrationService) StartOAuth(ctx context.Context, provider, label string, opts ...RequestOption) (*OAuthStartResult, *Response, error)
- func (s *IntegrationService) Test(ctx context.Context, id string, opts ...RequestOption) (bool, *Response, error)
- func (s *IntegrationService) UpdateConfig(ctx context.Context, id string, params *ConnectionConfigParams, ...) (*IntegrationConnection, *Response, error)
- func (s *IntegrationService) WebhookSecret(ctx context.Context, id string, opts ...RequestOption) (*ConnectionWebhookSecret, *Response, error)
- type Invitation
- type InvitationPreview
- type InviteMemberParams
- type LeadSyncConnection
- type LeadSyncConnectionSummary
- type LeadSyncCreateParams
- type LeadSyncResult
- type LeadSyncService
- func (s *LeadSyncService) Connection(ctx context.Context, opts ...RequestOption) (*LeadSyncConnection, *Response, error)
- func (s *LeadSyncService) Create(ctx context.Context, params *LeadSyncCreateParams, opts ...RequestOption) (*LeadSyncSource, *Response, error)
- func (s *LeadSyncService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *LeadSyncService) Get(ctx context.Context, id string, opts ...RequestOption) (*LeadSyncSource, *Response, error)
- func (s *LeadSyncService) Preview(ctx context.Context, connectionID, sheetID, tabTitle string, ...) (*ContactImportPreview, *Response, error)
- func (s *LeadSyncService) Sources(ctx context.Context, opts ...RequestOption) ([]LeadSyncSource, *Response, error)
- func (s *LeadSyncService) SourcesForCampaign(ctx context.Context, campaignID string, opts ...RequestOption) ([]LeadSyncSource, *Response, error)
- func (s *LeadSyncService) Spreadsheet(ctx context.Context, connectionID, sheetID string, opts ...RequestOption) (*Spreadsheet, *Response, error)
- func (s *LeadSyncService) Sync(ctx context.Context, id string, opts ...RequestOption) (*LeadSyncResult, *Response, error)
- func (s *LeadSyncService) Update(ctx context.Context, id string, params *LeadSyncUpdateParams, ...) (*LeadSyncSource, *Response, error)
- type LeadSyncSource
- type LeadSyncUpdateParams
- type LimitRequest
- type LimitRequestParams
- type LimitsAndCounts
- type ListOptions
- type LoginParams
- type MCPServer
- type MCPServerParams
- type MCPServerUpdateParams
- type MCPTool
- type MailboxAllowance
- type MailboxBulkResult
- type MailboxBulkRow
- type MailboxBulkSummary
- type MailboxCredentials
- type MailboxSync
- type MailboxSyncCursor
- type MailboxSyncFolderCursor
- type MailboxSyncPolicy
- type MailboxSyncState
- type Meeting
- type MeetingCreateParams
- type MeetingListParams
- type MeetingService
- func (s *MeetingService) Create(ctx context.Context, params *MeetingCreateParams, opts ...RequestOption) (*Meeting, *Response, error)
- func (s *MeetingService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *MeetingService) List(ctx context.Context, params *MeetingListParams, opts ...RequestOption) (*Page[Meeting], error)
- func (s *MeetingService) Summary(ctx context.Context, opts ...RequestOption) (*MeetingsSummary, *Response, error)
- type MeetingsSummary
- type Member
- type MemberRole
- type MessageParams
- type MetaService
- func (s *MetaService) GatewayTicket(ctx context.Context, opts ...RequestOption) (*GatewayTicket, *Response, error)
- func (s *MetaService) Identity(ctx context.Context, opts ...RequestOption) (*Identity, *Response, error)
- func (s *MetaService) Plans(ctx context.Context, opts ...RequestOption) ([]Plan, *Response, error)
- func (s *MetaService) Realtime(ctx context.Context, opts ...RequestOption) (*RealtimeInfo, *Response, error)
- func (s *MetaService) Timezones(ctx context.Context, opts ...RequestOption) ([]Timezone, *Response, error)
- type MiniCampaign
- type MiniCategory
- type NodePosition
- type Notification
- type NotificationEmailDelivery
- type NotificationFeed
- type NotificationPreferences
- type NotificationPreferencesResult
- type OAuth2Config
- func (c *OAuth2Config) AuthCodeURL(state string, opts ...AuthCodeOption) string
- func (c *OAuth2Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error)
- func (c *OAuth2Config) NewClient(ctx context.Context, t *Token, opts ...Option) (*Client, error)
- func (c *OAuth2Config) Refresh(ctx context.Context, refreshToken string) (*Token, error)
- func (c *OAuth2Config) Revoke(ctx context.Context, token string) error
- func (c *OAuth2Config) TokenSource(ctx context.Context, t *Token) TokenSource
- type OAuth2Endpoint
- type OAuth2Error
- type OAuthApp
- type OAuthAppParams
- type OAuthAppService
- func (s *OAuthAppService) Authorize(ctx context.Context, params *AuthorizeParams, opts ...RequestOption) (string, *Response, error)
- func (s *OAuthAppService) AuthorizeDetails(ctx context.Context, query url.Values, opts ...RequestOption) (*ConsentInfo, *Response, error)
- func (s *OAuthAppService) AuthorizedApps(ctx context.Context, opts ...RequestOption) ([]AuthorizedApp, *Response, error)
- func (s *OAuthAppService) Create(ctx context.Context, params *OAuthAppParams, opts ...RequestOption) (*OAuthAppWithSecret, *Response, error)
- func (s *OAuthAppService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *OAuthAppService) Get(ctx context.Context, id string, opts ...RequestOption) (*OAuthApp, *Response, error)
- func (s *OAuthAppService) List(ctx context.Context, opts ...RequestOption) ([]OAuthApp, *Response, error)
- func (s *OAuthAppService) RegisterDynamicClient(ctx context.Context, params *DynamicClientParams, opts ...RequestOption) (*DynamicClient, *Response, error)
- func (s *OAuthAppService) RevokeAuthorizedApp(ctx context.Context, applicationID string, opts ...RequestOption) (*Response, error)
- func (s *OAuthAppService) RotateSecret(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
- func (s *OAuthAppService) RotateWebhookSecret(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
- func (s *OAuthAppService) Update(ctx context.Context, id string, params *OAuthAppParams, opts ...RequestOption) (*OAuthApp, *Response, error)
- func (s *OAuthAppService) UploadLogo(ctx context.Context, file *FileUpload, opts ...RequestOption) (string, *Response, error)
- func (s *OAuthAppService) WebhookDeliveries(ctx context.Context, id string, params *WebhookDeliveryListParams, ...) (*Page[WebhookDelivery], error)
- func (s *OAuthAppService) WebhookEndpoints(ctx context.Context, id string, opts ...RequestOption) ([]Webhook, *Response, error)
- func (s *OAuthAppService) WebhookSecret(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
- type OAuthAppWithSecret
- type OAuthStartResult
- type OnboardingParams
- type Option
- func WithAPIKey(key string) Option
- func WithAccessToken(token string) Option
- func WithAuthenticator(a Authenticator) Option
- func WithBaseURL(raw string) Option
- func WithHTTPClient(hc *http.Client) Option
- func WithHeader(key, value string) Option
- func WithMaxRetries(n int) Option
- func WithRetryWaitBounds(minWait, maxWait time.Duration) Option
- func WithTokenSource(src TokenSource) Option
- func WithUserAgent(product string) Option
- type OrgArchiveInfo
- type OrgArchiveUser
- type OrgDataGroupInfo
- type OrgExportJob
- type OrgExportParams
- type OrgImportJob
- type OrgImportParams
- type OrgImportPreflight
- type OrgRisk
- type OrgTransferCatalog
- type Organization
- type OrganizationCounts
- type OrganizationCreateParams
- type OrganizationLimits
- type OrganizationService
- func (s *OrganizationService) AcceptInvitation(ctx context.Context, token string, opts ...RequestOption) (*Member, *Response, error)
- func (s *OrganizationService) CancelDeletion(ctx context.Context, reason string, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) CancelInvitation(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) CancelLimitRequest(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) Create(ctx context.Context, params *OrganizationCreateParams, opts ...RequestOption) (*Organization, *Response, error)
- func (s *OrganizationService) CreateExport(ctx context.Context, params *OrgExportParams, opts ...RequestOption) (*OrgExportJob, *Response, error)
- func (s *OrganizationService) CreateImport(ctx context.Context, file *FileUpload, params *OrgImportParams, ...) (*OrgImportJob, *Response, error)
- func (s *OrganizationService) CreateRole(ctx context.Context, params *RoleCreateParams, opts ...RequestOption) (*Role, *Response, error)
- func (s *OrganizationService) Current(ctx context.Context, opts ...RequestOption) (*OrganizationWithLimits, *Response, error)
- func (s *OrganizationService) DangerZone(ctx context.Context, opts ...RequestOption) (*DangerZoneStatus, *Response, error)
- func (s *OrganizationService) DeleteAvatar(ctx context.Context, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) DeleteExport(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) DeleteRole(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) DownloadExport(ctx context.Context, id string, w io.Writer, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) Export(ctx context.Context, id string, opts ...RequestOption) (*OrgExportJob, *Response, error)
- func (s *OrganizationService) Exports(ctx context.Context, opts ...RequestOption) ([]OrgExportJob, *Response, error)
- func (s *OrganizationService) Import(ctx context.Context, id string, opts ...RequestOption) (*OrgImportJob, *Response, error)
- func (s *OrganizationService) Imports(ctx context.Context, opts ...RequestOption) ([]OrgImportJob, *Response, error)
- func (s *OrganizationService) InvitationLink(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
- func (s *OrganizationService) Invitations(ctx context.Context, opts ...RequestOption) ([]Invitation, *Response, error)
- func (s *OrganizationService) Invite(ctx context.Context, params *InviteMemberParams, opts ...RequestOption) (*Invitation, *Response, error)
- func (s *OrganizationService) LimitRequests(ctx context.Context, orgID string, opts ...RequestOption) ([]LimitRequest, *Response, error)
- func (s *OrganizationService) Limits(ctx context.Context, opts ...RequestOption) (*LimitsAndCounts, *Response, error)
- func (s *OrganizationService) List(ctx context.Context, opts ...RequestOption) ([]Member, *Response, error)
- func (s *OrganizationService) Members(ctx context.Context, opts ...RequestOption) ([]Member, *Response, error)
- func (s *OrganizationService) MyInvitations(ctx context.Context, opts ...RequestOption) ([]Invitation, *Response, error)
- func (s *OrganizationService) PreflightImport(ctx context.Context, file *FileUpload, passphrase string, ...) (*OrgImportPreflight, *Response, error)
- func (s *OrganizationService) PreviewInvitation(ctx context.Context, token string, opts ...RequestOption) (*InvitationPreview, *Response, error)
- func (s *OrganizationService) RemoveMember(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) RequestLimitIncrease(ctx context.Context, orgID string, params *LimitRequestParams, ...) (*LimitRequest, *Response, error)
- func (s *OrganizationService) Risk(ctx context.Context, opts ...RequestOption) (*OrgRisk, *Response, error)
- func (s *OrganizationService) Roles(ctx context.Context, opts ...RequestOption) ([]Role, *Response, error)
- func (s *OrganizationService) ScheduleDeletion(ctx context.Context, params *ScheduleDeletionParams, opts ...RequestOption) (*ScheduledDeletion, *Response, error)
- func (s *OrganizationService) Switch(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) TransferGroups(ctx context.Context, opts ...RequestOption) (*OrgTransferCatalog, *Response, error)
- func (s *OrganizationService) TransferOwnership(ctx context.Context, newOwnerUserID string, opts ...RequestOption) (*Response, error)
- func (s *OrganizationService) Update(ctx context.Context, params *OrganizationUpdateParams, opts ...RequestOption) (*Organization, *Response, error)
- func (s *OrganizationService) UpdateMember(ctx context.Context, id string, params *UpdateMemberParams, ...) (*Member, *Response, error)
- func (s *OrganizationService) UpdateRole(ctx context.Context, id string, params *RoleUpdateParams, ...) (*Role, *Response, error)
- func (s *OrganizationService) UploadAvatar(ctx context.Context, file *FileUpload, opts ...RequestOption) (string, *Response, error)
- type OrganizationUpdateParams
- type OrganizationWithLimits
- type OutreachService
- type OutreachSettings
- type OverallStats
- type Page
- type Pagination
- type PasskeyCredential
- type PasskeyLoginChallenge
- type PendingTool
- type Permission
- type PermissionCatalog
- type PermissionPresets
- type Pipeline
- type PipelineCreateParams
- type PipelineStage
- type PipelineUpdateParams
- type Plan
- type PlanChangePreview
- type PoolLinkCode
- type PoolLinkCodeGrant
- type PoolLinkInstance
- type PoolLinkInstanceInfo
- type PoolLinkInstanceList
- type PoolLinkMailboxState
- type PoolLinkOrganization
- type PoolLinkPlan
- type PoolLinkPollResult
- type PoolLinkService
- func (s *PoolLinkService) ApproveCode(ctx context.Context, userCode, organizationID string, opts ...RequestOption) (*PoolLinkInstance, *Response, error)
- func (s *PoolLinkService) DenyCode(ctx context.Context, userCode string, opts ...RequestOption) (*Response, error)
- func (s *PoolLinkService) DescribeCode(ctx context.Context, userCode string, opts ...RequestOption) (*PoolLinkCode, *Response, error)
- func (s *PoolLinkService) ListInstances(ctx context.Context, opts ...RequestOption) (*PoolLinkInstanceList, *Response, error)
- func (s *PoolLinkService) Poll(ctx context.Context, deviceCode string, opts ...RequestOption) (*PoolLinkPollResult, *Response, error)
- func (s *PoolLinkService) RevokeInstance(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *PoolLinkService) StartCode(ctx context.Context, params *PoolLinkStartParams, opts ...RequestOption) (*PoolLinkCodeGrant, *Response, error)
- func (s *PoolLinkService) WaitForApproval(ctx context.Context, grant *PoolLinkCodeGrant, opts ...RequestOption) (*PoolLinkPollResult, error)
- type PoolLinkStartParams
- type PoolLinkWarmupHealth
- type PoolLinkWarmupRampHold
- type PoolLinkWarmupSettings
- type PoolLinkWarmupStatus
- type PoolLinkWorkspaceMailbox
- type PreflightCheck
- type PreflightResult
- type PreflightValidationSettings
- type ProfileUpdateParams
- type ProviderPlacement
- type PushContactResult
- type PushResult
- type RateLimit
- type RealtimeInfo
- type RealtimeRateLimits
- type ReferralAttribution
- type ReferralCode
- type ReferralEarning
- type ReferralSummary
- type ReplyIntentSettings
- type RequestOption
- type ResearchArtifact
- type ResearchCompany
- type ResearchHook
- type ResearchPerson
- type ResearchResult
- type ResearchRun
- type ResearchSignal
- type Response
- type Role
- type RoleCreateParams
- type RoleUpdateParams
- type SMTPIMAPBulkParams
- type SMTPIMAPCredentialsParams
- type SMTPIMAPParams
- type SSORedirect
- type ScheduleDeletionParams
- type ScheduleWindows
- type ScheduledDeletion
- type ScheduledSend
- type Segment
- type SegmentAddToCampaignResult
- type SegmentCondition
- type SegmentCreateParams
- type SegmentFieldKind
- type SegmentFieldSpec
- type SegmentMatch
- type SegmentMemberMode
- type SegmentOperator
- type SegmentOverride
- type SegmentPreviewParams
- type SegmentPreviewResult
- type SegmentService
- func (s *SegmentService) AddToCampaign(ctx context.Context, id, campaignID string, opts ...RequestOption) (*SegmentAddToCampaignResult, *Response, error)
- func (s *SegmentService) Create(ctx context.Context, params *SegmentCreateParams, opts ...RequestOption) (*Segment, *Response, error)
- func (s *SegmentService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *SegmentService) Fields(ctx context.Context, opts ...RequestOption) ([]SegmentFieldSpec, *Response, error)
- func (s *SegmentService) Get(ctx context.Context, id string, opts ...RequestOption) (*Segment, *Response, error)
- func (s *SegmentService) List(ctx context.Context, opts ...RequestOption) ([]Segment, *Response, error)
- func (s *SegmentService) MemberModes(ctx context.Context, id string, contactIDs []string, opts ...RequestOption) (map[string]SegmentMemberMode, *Response, error)
- func (s *SegmentService) Overrides(ctx context.Context, id string, opts ...RequestOption) ([]SegmentOverride, *Response, error)
- func (s *SegmentService) Preview(ctx context.Context, params *SegmentPreviewParams, opts ...RequestOption) (*SegmentPreviewResult, *Response, error)
- func (s *SegmentService) SetMembers(ctx context.Context, id string, contactIDs []string, mode SegmentMemberMode, ...) (int, *Response, error)
- func (s *SegmentService) Update(ctx context.Context, id string, params *SegmentUpdateParams, ...) (*Segment, *Response, error)
- type SegmentUpdateParams
- type SendEmailParams
- type SendLifecycleState
- type SendResult
- type SendTimeOptimizationSettings
- type SendingBehavior
- type SendingBehaviorUpdateParams
- type Session
- type SetupParams
- type SkillCreateParams
- type SkillService
- func (s *SkillService) Create(ctx context.Context, params *SkillCreateParams, opts ...RequestOption) (*AISkill, *Response, error)
- func (s *SkillService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *SkillService) List(ctx context.Context, opts ...RequestOption) ([]AISkill, *Response, error)
- func (s *SkillService) Update(ctx context.Context, id string, params *SkillUpdateParams, ...) (*AISkill, *Response, error)
- type SkillUpdateParams
- type Spreadsheet
- type SpreadsheetTab
- type StageCreateParams
- type StageUpdateParams
- type Step
- type StepAnalytics
- type StepInput
- type StepPosition
- type StepUpdateParams
- type StorageUsage
- type Subscription
- type SubscriptionStatus
- type SubscriptionWithLimits
- type SuppressedRecipient
- type SuppressionAddParams
- type SuppressionAddResult
- type SuppressionEntry
- type SuppressionKind
- type SuppressionListParams
- type SuppressionService
- func (s *SuppressionService) Add(ctx context.Context, params *SuppressionAddParams, opts ...RequestOption) (*SuppressionAddResult, *Response, error)
- func (s *SuppressionService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *SuppressionService) List(ctx context.Context, params *SuppressionListParams, opts ...RequestOption) (*Page[SuppressedRecipient], error)
- type SuppressionSource
- type SyncRun
- type TaskReliabilitySettings
- type TaskSearchParams
- type TaskService
- type TaskTypeCreateParams
- type TaskTypeUpdateParams
- type TasksSummary
- type Team
- type TeamCreateParams
- type TeamMember
- type TeamService
- func (s *TeamService) AddMember(ctx context.Context, id, userID string, opts ...RequestOption) (*Team, *Response, error)
- func (s *TeamService) Create(ctx context.Context, params *TeamCreateParams, opts ...RequestOption) (*Team, *Response, error)
- func (s *TeamService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *TeamService) Get(ctx context.Context, id string, opts ...RequestOption) (*Team, *Response, error)
- func (s *TeamService) List(ctx context.Context, opts ...RequestOption) ([]Team, *Response, error)
- func (s *TeamService) RemoveMember(ctx context.Context, id, userID string, opts ...RequestOption) (*Response, error)
- func (s *TeamService) Update(ctx context.Context, id string, params *TeamUpdateParams, ...) (*Team, *Response, error)
- type TeamUpdateParams
- type Template
- type TemplateCreateParams
- type TemplateField
- type TemplateIssue
- type TemplatePreviewAttachment
- type TemplatePreviewFrom
- type TemplatePreviewInput
- type TemplatePreviewParams
- type TemplatePreviewResult
- type TemplateRenderResult
- type TemplateScore
- type TemplateScoreParams
- type TemplateService
- func (s *TemplateService) Create(ctx context.Context, params *TemplateCreateParams, opts ...RequestOption) (*Template, *Response, error)
- func (s *TemplateService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *TemplateService) Duplicate(ctx context.Context, id string, opts ...RequestOption) (*Template, *Response, error)
- func (s *TemplateService) Get(ctx context.Context, id string, opts ...RequestOption) (*Template, *Response, error)
- func (s *TemplateService) List(ctx context.Context, query string, opts ...RequestOption) ([]Template, *Response, error)
- func (s *TemplateService) Render(ctx context.Context, id string, variables map[string]string, ...) (*TemplateRenderResult, *Response, error)
- func (s *TemplateService) Reorder(ctx context.Context, ids []string, opts ...RequestOption) ([]Template, *Response, error)
- func (s *TemplateService) Score(ctx context.Context, params *TemplateScoreParams, opts ...RequestOption) (*TemplateScore, *Response, error)
- func (s *TemplateService) Update(ctx context.Context, id string, params *TemplateUpdateParams, ...) (*Template, *Response, error)
- type TemplateUpdateParams
- type TestEmailParams
- type TestEmailResult
- type TimeInterval
- type TimelineEvent
- type TimelineParams
- type Timezone
- type Token
- type TokenSource
- type TrackingDomainStatus
- type TrialStatus
- type TwoFAEnrollment
- type TwoFARecoveryCodes
- type TwoFAStatus
- type UniboxComposeParams
- type UniboxFolderCount
- type UniboxLabelCount
- type UniboxListParams
- type UniboxMailboxCount
- type UniboxMessage
- type UniboxOverview
- type UniboxReplyParams
- type UniboxService
- func (s *UniboxService) AgentDrafts(ctx context.Context, opts ...RequestOption) ([]AgentDraft, *Response, error)
- func (s *UniboxService) ApproveAgentDraft(ctx context.Context, id, body string, opts ...RequestOption) (*SendResult, *Response, error)
- func (s *UniboxService) CancelScheduled(ctx context.Context, taskID string, opts ...RequestOption) (*Response, error)
- func (s *UniboxService) Compose(ctx context.Context, params *UniboxComposeParams, opts ...RequestOption) (*ComposeResult, *Response, error)
- func (s *UniboxService) ComposeCandidates(ctx context.Context, to string, opts ...RequestOption) (*ComposeCandidates, *Response, error)
- func (s *UniboxService) DeleteDraft(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *UniboxService) DiscardAgentDraft(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *UniboxService) DraftCompose(ctx context.Context, to, subject, instruction string, opts ...RequestOption) (*AIDraft, *Response, error)
- func (s *UniboxService) DraftReply(ctx context.Context, threadID, instruction string, opts ...RequestOption) (*AIDraft, *Response, error)
- func (s *UniboxService) Drafts(ctx context.Context, opts ...RequestOption) ([]ComposeDraft, *Response, error)
- func (s *UniboxService) Get(ctx context.Context, id string, opts ...RequestOption) (*UniboxMessage, *Response, error)
- func (s *UniboxService) List(ctx context.Context, params *UniboxListParams, opts ...RequestOption) (*Page[UniboxThread], error)
- func (s *UniboxService) MarkFolderSeen(ctx context.Context, folder string, seen bool, opts ...RequestOption) (*Response, error)
- func (s *UniboxService) MarkSeen(ctx context.Context, emailIDs []string, seen bool, opts ...RequestOption) (*Response, error)
- func (s *UniboxService) Overview(ctx context.Context, opts ...RequestOption) (*UniboxOverview, *Response, error)
- func (s *UniboxService) Reply(ctx context.Context, params *UniboxReplyParams, opts ...RequestOption) (*SendResult, *Response, error)
- func (s *UniboxService) SaveDraft(ctx context.Context, id string, params *ComposeDraftParams, ...) (*Response, error)
- func (s *UniboxService) Scheduled(ctx context.Context, threadID string, opts ...RequestOption) ([]ScheduledSend, *Response, error)
- func (s *UniboxService) SetThreadLabels(ctx context.Context, threadID string, categoryIDs []string, ...) ([]MiniCategory, *Response, error)
- func (s *UniboxService) Snooze(ctx context.Context, threadID string, until time.Time, opts ...RequestOption) (*UniboxSnooze, *Response, error)
- func (s *UniboxService) Snoozes(ctx context.Context, opts ...RequestOption) ([]UniboxSnooze, *Response, error)
- func (s *UniboxService) Thread(ctx context.Context, threadID, emailID string, params *ListOptions, ...) (*Page[UniboxMessage], error)
- func (s *UniboxService) ThreadLabels(ctx context.Context, threadID string, opts ...RequestOption) ([]MiniCategory, *Response, error)
- func (s *UniboxService) UnseenCount(ctx context.Context, emailID string, opts ...RequestOption) (int, *Response, error)
- func (s *UniboxService) Unsnooze(ctx context.Context, threadID string, opts ...RequestOption) (*Response, error)
- type UniboxSnooze
- type UniboxThread
- type UnsubscribeSettings
- type UpdateMemberParams
- type UpsertContactConfig
- type UsageOverview
- type User
- type UserSession
- type VerifyResult
- type WarmupAnalytics
- type WarmupAppealParams
- type WarmupAppealResult
- type WarmupBanStatus
- type WarmupDailyStat
- type WarmupDomainPlacement
- type WarmupHealth
- type WarmupRampHold
- type WarmupRoutingRule
- type WarmupRoutingRuleParams
- type WarmupRoutingService
- func (s *WarmupRoutingService) Create(ctx context.Context, params *WarmupRoutingRuleParams, opts ...RequestOption) (*WarmupRoutingRule, *Response, error)
- func (s *WarmupRoutingService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *WarmupRoutingService) List(ctx context.Context, opts ...RequestOption) ([]WarmupRoutingRule, *Response, error)
- func (s *WarmupRoutingService) Update(ctx context.Context, id string, params *WarmupRoutingRuleParams, ...) (*WarmupRoutingRule, *Response, error)
- type WarmupStatus
- type WarmupSummary
- type Webhook
- type WebhookChallengePayload
- type WebhookCreateParams
- type WebhookDelivery
- type WebhookDeliveryListParams
- type WebhookDrop
- type WebhookEndpointList
- type WebhookEvent
- type WebhookEventDescriptor
- type WebhookEventName
- type WebhookService
- func (s *WebhookService) ConstructEvent(payload []byte, signatureHeader, secret string) (*WebhookEvent, error)
- func (s *WebhookService) Create(ctx context.Context, params *WebhookCreateParams, opts ...RequestOption) (*WebhookWithSecret, *Response, error)
- func (s *WebhookService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- func (s *WebhookService) Deliveries(ctx context.Context, params *WebhookDeliveryListParams, opts ...RequestOption) (*Page[WebhookDelivery], error)
- func (s *WebhookService) Drops(ctx context.Context, opts ...RequestOption) ([]WebhookDrop, *Response, error)
- func (s *WebhookService) EndpointDeliveries(ctx context.Context, id string, params *WebhookDeliveryListParams, ...) (*Page[WebhookDelivery], error)
- func (s *WebhookService) EventTypes(ctx context.Context, opts ...RequestOption) ([]WebhookEventDescriptor, *Response, error)
- func (s *WebhookService) List(ctx context.Context, opts ...RequestOption) (*WebhookEndpointList, *Response, error)
- func (s *WebhookService) Redeliver(ctx context.Context, deliveryID string, opts ...RequestOption) (*Response, error)
- func (s *WebhookService) RotateSecret(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
- func (s *WebhookService) Update(ctx context.Context, id string, params *WebhookUpdateParams, ...) (*Webhook, *Response, error)
- func (s *WebhookService) Verify(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
- type WebhookUpdateParams
- type WebhookWithSecret
- type WebsiteTrackingService
- func (s *WebsiteTrackingService) RotateKey(ctx context.Context, opts ...RequestOption) (*WebsiteTrackingSettings, *Response, error)
- func (s *WebsiteTrackingService) Settings(ctx context.Context, opts ...RequestOption) (*WebsiteTrackingSettings, *Response, error)
- func (s *WebsiteTrackingService) UpdateSettings(ctx context.Context, params *WebsiteTrackingUpdateParams, ...) (*WebsiteTrackingSettings, *Response, error)
- type WebsiteTrackingSettings
- type WebsiteTrackingUpdateParams
- type WriteParams
Examples ¶
Constants ¶
const ( AdvisorCritical = "critical" AdvisorHigh = "high" AdvisorMedium = "medium" AdvisorLow = "low" )
Finding severities returned in AdvisorFinding.Severity.
const ( AdvisorCategoryDeliverability = "deliverability" AdvisorCategoryMailbox = "mailbox" AdvisorCategoryWarmup = "warmup" AdvisorCategoryCampaign = "campaign" AdvisorCategoryCopy = "copy" AdvisorCategoryList = "list" )
Finding categories returned in AdvisorFinding.Category.
const ( AdvisorSurfaceCampaigns = "campaigns" AdvisorSurfaceMailboxes = "emails" AdvisorSurfaceDeliverability = "deliverability" AdvisorSurfaceContacts = "contacts" AdvisorSurfaceAnalytics = "analytics" AdvisorSurfaceSettings = "settings" )
Surfaces a finding is shown on, returned in AdvisorFinding.Surface.
const ( AdvisorStatusOpen = "open" AdvisorStatusSnoozed = "snoozed" AdvisorStatusDismissed = "dismissed" AdvisorStatusApplied = "applied" AdvisorStatusResolved = "resolved" )
Finding states returned in AdvisorFinding.Status.
const ( // AIVariableInstant resolves from what is already known about the contact. AIVariableInstant = "instant" // AIVariableResearch researches the contact first, and costs more. AIVariableResearch = "research" )
AI variable resolution modes for AIVariableParams.Mode.
const ( Period7Days = "7d" Period30Days = "30d" Period90Days = "90d" )
Rolling windows accepted by AnalyticsService.Dashboard.
const ( UsagePeriodDay = "day" UsagePeriodWeek = "week" UsagePeriodMonth = "month" )
Usage windows accepted by AnalyticsService.Usage.
const ( BandHealthy = "healthy" BandWatch = "watch" BandThrottled = "throttled" BandQuarantined = "quarantined" BandBlocked = "blocked" )
Deliverability health bands returned in DeliverabilityDashboard.Band and in the per-mailbox and per-campaign breakdowns.
const ( // PermReadEmails grants reading mailboxes and their settings. PermReadEmails uint64 = 1 << iota // PermReadCampaigns grants reading campaigns and their steps. PermReadCampaigns // PermReadContacts grants reading contacts, segments, notes and // activities. PermReadContacts // PermReadUnibox grants reading the unified inbox. PermReadUnibox // PermReadAnalytics grants reading analytics and statistics. PermReadAnalytics // PermWriteEmails grants modifying mailbox settings. PermWriteEmails // PermWriteCampaigns grants creating and editing campaigns and steps. PermWriteCampaigns // PermWriteContacts grants creating and editing contacts, segments, notes // and activities. PermWriteContacts // PermWriteUnibox grants marking messages seen and sending replies. PermWriteUnibox // PermBulkContacts grants bulk contact import, export and delete. It is // separate so a key can read and write without bulk power. PermBulkContacts // PermBulkCampaigns grants bulk campaign operations. PermBulkCampaigns // PermRealtimeSubscribe grants subscribing to the realtime gateway. PermRealtimeSubscribe // PermWebhooks grants managing webhook endpoints. PermWebhooks // PermAPIKeys grants creating, listing and revoking API keys, so an // integration can rotate its own credentials. PermAPIKeys // PermSendCampaigns grants starting and stopping campaigns. It is separate // from PermWriteCampaigns because starting one actually sends mail. PermSendCampaigns // PermReadTemplates grants reading reply templates. PermReadTemplates // PermWriteTemplates grants creating and editing reply templates. PermWriteTemplates // PermReadCRM grants reading pipelines, deals and CRM tasks. PermReadCRM // PermWriteCRM grants creating and editing pipelines, deals and CRM tasks. PermWriteCRM // PermReadAuditLogs grants reading the organization audit trail. PermReadAuditLogs // PermIntegrations grants connecting and managing third-party integrations // and automations. PermIntegrations // PermWarmupRouting grants managing warmup routing rules. PermWarmupRouting // PermAIAgent grants running the AI assistant and the MCP tool surface. PermAIAgent // PermAIResearch grants running AI contact research. PermAIResearch )
API permission bits. A key's grant is the bitwise OR of the scopes it holds, which is what travels in APIKey.Permissions:
perms := warmbly.PermReadCampaigns | warmbly.PermWriteCampaigns
These are distinct from the organization role permissions that gate a human session.
const ( // PermReadOnly grants every read scope and nothing else. PermReadOnly = PermReadEmails | PermReadCampaigns | PermReadContacts | PermReadUnibox | PermReadAnalytics | PermReadTemplates | PermReadCRM | PermReadAuditLogs // PermFullAccess grants every scope this SDK release knows about. A key // minted with it will not pick up scopes added later. PermFullAccess = PermReadOnly | PermWriteEmails | PermWriteCampaigns | PermWriteContacts | PermWriteUnibox | PermBulkContacts | PermBulkCampaigns | PermSendCampaigns | PermWriteTemplates | PermWriteCRM | PermRealtimeSubscribe | PermWebhooks | PermAPIKeys | PermIntegrations | PermWarmupRouting | PermAIAgent | PermAIResearch )
Preset permission masks matching the presets the API advertises.
const ( APIKeyStatusActive = "active" APIKeyStatusRevoked = "revoked" APIKeyStatusExpired = "expired" )
API key lifecycle states returned in APIKey.Status.
const ( // MinRateLimitPerMinute and MaxRateLimitPerMinute bound an explicit // per-key request ceiling; DefaultRateLimitPerMinute is what a key gets // when it names none. MinRateLimitPerMinute = 1 MaxRateLimitPerMinute = 10000 DefaultRateLimitPerMinute = 60 // MaxAllowedIPs is the most entries an IP allow-list may hold, and // MaxAllowedEmailAccounts the most mailboxes a key may be pinned to. MaxAllowedIPs = 64 MaxAllowedEmailAccounts = 128 )
Bounds the server enforces on APIKeyCreateParams and APIKeyUpdateParams.
const ( IntervalMinute = "minute" IntervalHour = "hour" IntervalDay = "day" )
Bucket granularities accepted by APIKeyAnalyticsParams.Interval.
const ( // AgentEventTextDelta is an incremental chunk of the reply. AgentEventTextDelta = "text_delta" // AgentEventText is a complete block of reply text. AgentEventText = "text" // AgentEventToolStart announces a tool call beginning. AgentEventToolStart = "tool_start" // AgentEventToolResult carries what a tool returned. AgentEventToolResult = "tool_result" // AgentEventApprovalRequired pauses the run until // [AssistantService.Approve] answers. AgentEventApprovalRequired = "approval_required" // AgentEventError ends the run with a failure. AgentEventError = "error" // AgentEventDone ends the run normally. AgentEventDone = "done" )
Event types streamed during a run, in AgentEvent.Type.
const ( // ApprovalApprove runs the paused tool call once. ApprovalApprove = "approve" // ApprovalDeny abandons it and lets the assistant continue without it. ApprovalDeny = "deny" // ApprovalAlwaysAllow runs it and stops asking for that tool in this // session. ApprovalAlwaysAllow = "always_allow" )
Decisions accepted by AssistantService.Approve.
const ( AuditActionCreate = "create" AuditActionUpdate = "update" AuditActionDelete = "delete" AuditActionDuplicate = "duplicate" AuditActionSend = "send" // Lifecycle actions on a campaign or a mailbox's warmup. AuditActionStart = "start" AuditActionStop = "stop" AuditActionPause = "pause" AuditActionResume = "resume" // Credentials and connections. AuditActionRevoke = "revoke" AuditActionRotate = "rotate" AuditActionRotateKeys = "rotate_keys" AuditActionConnect = "connect" AuditActionDisconnect = "disconnect" AuditActionTest = "test" // Membership and ownership. AuditActionInvite = "invite" AuditActionRemove = "remove" AuditActionAssign = "assign" AuditActionTransfer = "transfer" // Bulk movement of data in and out of the workspace. AuditActionExport = "export" AuditActionImport = "import" // AuditActionAPICall records a call made with an API key, when the key is // configured to log its requests. AuditActionAPICall = "api_call" // AuditActionApply records an advisor recommendation being applied. AuditActionApply = "apply" )
Values for AuditLog.Action. The trail is append-only and the vocabulary grows, so treat an action you do not recognize as informational rather than failing on it.
const ( AuditEntityCampaign = "campaign" AuditEntityContact = "contact" AuditEntityEmailAccount = "email_account" AuditEntityAPIKey = "api_key" AuditEntityWebhook = "webhook" AuditEntityTemplate = "template" // AuditEntitySequence is a step within a campaign's sequence. The wire // value is "step". AuditEntitySequence = "step" AuditEntityOrganization = "organization" AuditEntityUser = "user" // Audiences and the do-not-contact list. AuditEntitySegment = "segment" AuditEntityForm = "form" AuditEntitySuppression = "suppression" // Labels. AuditEntityFolder = "folder" AuditEntityTag = "tag" AuditEntityCategory = "category" // Team and access. AuditEntityOrganizationMember = "organization_member" AuditEntityInvitation = "invitation" AuditEntityRole = "role" AuditEntityTeam = "team" // CRM. AuditEntityCRMPipeline = "crm_pipeline" AuditEntityCRMStage = "crm_stage" AuditEntityCRMDeal = "crm_deal" AuditEntityCRMTask = "crm_task" AuditEntityCRMNote = "crm_note" // Connections and flows. AuditEntityIntegration = "integration" AuditEntityAutomation = "automation" AuditEntityLeadSyncSource = "lead_sync_source" AuditEntityMeeting = "meeting" AuditEntityUnibox = "unibox" // Warmup and sending posture. AuditEntityWarmupRoutingRule = "warmup_routing_rule" // AuditEntityOrgRisk is a change in the workspace's sending posture. AuditEntityOrgRisk = "org_risk" // AI. AuditEntityAISession = "ai_session" AuditEntityAISkill = "ai_skill" AuditEntityMCPServer = "mcp_server" AuditEntityAdvisorFinding = "advisor_finding" // Billing. AuditEntitySubscription = "subscription" AuditEntityReferral = "referral" AuditEntityReferralCredit = "referral_credit" AuditEntityCreditPurchase = "credit_purchase" AuditEntityCreditGrant = "credit_grant" // Workspace settings and the archives used to move a workspace between // instances. AuditEntitySettings = "settings" AuditEntityOrgArchive = "org_archive" // The self-hosted warmup pool link, from the cloud side // ([AuditEntityPoolLink]) and the instance side ([AuditEntityCloudLink]). AuditEntityPoolLink = "pool_link" AuditEntityCloudLink = "cloud_link" )
Values for AuditLog.EntityType. As with actions, the vocabulary grows; branch on the ones you care about and pass the rest through.
The platform's own entities (workers, releases, instance settings) are audited too, but on the operator's trail rather than any organization's, so they never appear here.
const ( // LoginCodeAlways emails a code on every password sign-in. LoginCodeAlways = "always" // LoginCodeNewDevice emails a code only from a browser the account has // not signed in from before, or when the sign-in looks anomalous. LoginCodeNewDevice = "new_device" // LoginCodeOff never emails a code: [AuthService.Login] returns the // tokens directly. LoginCodeOff = "off" )
Login-code policies returned in AuthConfig.LoginCode.
const ( // RegistrationOpen means anyone may create an account. RegistrationOpen = "true" // RegistrationInviteOnly means a signup needs an invitation token // ([LoginParams.Invite]). RegistrationInviteOnly = "invite_only" // RegistrationClosed means signups are off and invitations do not // override it. RegistrationClosed = "false" )
Registration policies returned in AuthConfig.Registration.
const ( SSOProviderOIDC = "oidc" SSOProviderGoogle = "google" SSOProviderApple = "apple" )
Browser SSO providers accepted by AuthService.BeginSSO and listed in AuthConfig.Providers.
const ( // CLIAuthPending means no member has decided yet. CLIAuthPending = "pending" // CLIAuthApproved means a member approved; the poll that sees it carries // the key. CLIAuthApproved = "approved" // CLIAuthClaimed means the key has already been handed out and the code // is spent. CLIAuthClaimed = "claimed" // CLIAuthDenied means a member declined. CLIAuthDenied = "denied" )
CLI device-flow handshake states returned in CLIAuthPoll.Status and CLIAuthRequest.Status.
const ( NotifInboundReply = "inbound_reply" NotifInboundOOO = "inbound_out_of_office" NotifHealthBounce = "health_bounce" NotifHealthComplaint = "health_complaint" NotifWorkerDowntime = "health_worker_downtime" NotifSecuritySignIn = "security_new_signin" NotifBillingAlert = "billing_alert" NotifTeamActivity = "team_activity" // NotifCampaignPaused fires when the platform pauses a campaign on its // own, for example when an auto-pause guardrail is breached. NotifCampaignPaused = "campaign_paused" // NotifDomainAuth fires when a sending domain starts failing SPF or // DMARC: the warning before the send gate applies. NotifDomainAuth = "health_domain_auth" )
Notification categories used in Notification.Category and the preference map.
const ( // TriggerInboundWebhook runs the automation when an external system POSTs // JSON to its [Automation.InboundURL]. It is a trigger only and is never // delivered outbound. TriggerInboundWebhook = "inbound.webhook" // TriggerContactCreated fires for every new contact, whatever created it // (import, form, API, another automation). The event carries the contact // fields plus source, source_detail, custom_fields, campaign_ids and // category_ids, and no campaign. TriggerContactCreated = "contact.created" // TriggerFormSubmitted fires when a hosted form is submitted. The event // carries form_id, form_name, submission_id, source_url and the raw // answers under data, alongside the contact fields the answers mapped to. TriggerFormSubmitted = "form.submitted" // TriggerReplyReceived fires on an inbound campaign reply, with intent // and confidence from the classifier. TriggerReplyReceived = "campaign.reply_received" )
Trigger events accepted in Automation.TriggerEvent. Any Event* constant from the webhook catalog can be a trigger; these are the ones with dedicated semantics or no webhook twin.
const ( ActionSlackNotify = "slack.notify" ActionDiscordNotify = "discord.notify" ActionHubSpotUpsert = "hubspot.upsert_contact" ActionPipedriveUpsert = "pipedrive.upsert_person" ActionSalesforceUpsert = "salesforce.upsert_contact" ActionCloseUpsert = "close.upsert_lead" ActionWebhookPing = "webhook.ping" ActionAddTag = "warmbly.add_tag" ActionRemoveTag = "warmbly.remove_tag" ActionCreateTask = "warmbly.create_task" ActionCreateDeal = "warmbly.create_deal" ActionMoveDealStage = "warmbly.move_deal_stage" ActionUnsubscribe = "warmbly.unsubscribe" // ActionLabelEmail applies conversation labels to the thread a reply // event belongs to; on triggers without a thread it is a logged no-op. ActionLabelEmail = "warmbly.label_email" // ActionRunAutomation launches another automation with the current event // data, one hop deeper in the chain. ActionRunAutomation = "warmbly.run_automation" // ActionSetVariables computes named values from templates and writes them // into the event data for later nodes. ActionSetVariables = "warmbly.set_variables" // ActionFireEvent publishes a custom event to the realtime gateway. ActionFireEvent = "warmbly.fire_event" // ActionUpsertContact creates a contact from templated event fields, or // enriches the one already holding that email, then tags it and enrolls // it in a campaign. It is the one action that can run before the event has // a contact: the written contact becomes the event's contact for every // node after it. Configure it with [UpsertContactConfig]. ActionUpsertContact = "warmbly.upsert_contact" // ActionAddToCampaign enrolls the event's contact in a campaign and wakes // it. Configure it with [AddToCampaignConfig]. ActionAddToCampaign = "warmbly.add_to_campaign" // ActionAIStep is the unified AI node (classify, extract, generate or a // bounded tool-using agent); ActionAISwitch routes to exactly one named // case. Both spend AI credits, including on a dry run. ActionAIStep = "warmbly.ai_step" ActionAISwitch = "warmbly.ai_switch" )
Action identifiers for AutomationNode.Action. Provider actions run against the node's ConnectionID; the built-in "warmbly." actions need no connection and run against the contact the event resolved (contact_id or contact_email in the event data).
const ( // IfExistsUpdate enriches the existing contact: rendered fields that are // empty never erase what the contact already has. The default. IfExistsUpdate = "update" // IfExistsSkip leaves the existing contact untouched but still makes it // the event's contact for the nodes that follow. IfExistsSkip = "skip" )
Policies accepted in UpsertContactConfig.IfExists.
const ( // NodeTrigger is the entry point; there is exactly one, conventionally // with the id "trigger". NodeTrigger = "trigger" // NodeCondition branches on the event data. NodeCondition = "condition" // NodeAction performs work, against a connection or built in. NodeAction = "action" // NodeStop is a terminal marker: a path routed into it ends. It carries // no action or condition. NodeStop = "stop" )
Node kinds in an automation graph.
const ( // ConditionField tests one event-data key, named by Key, with Operator // and Value. ConditionField = "field" // ConditionExpression evaluates Expression, a Go-template predicate, and // takes the true branch when it renders non-empty and not "false". ConditionExpression = "expression" // ConditionAI asks the model the yes/no question in Prompt about the // event. It costs one AI credit per evaluation. ConditionAI = "ai" // ConditionRandom is a deterministic percentage split; use // [ConditionOpChance] with Value as the percentage. ConditionRandom = "random" // ConditionIntent tests the reply classifier's intent. ConditionIntent = "intent" // ConditionConfidence tests the classifier's confidence, a float. ConditionConfidence = "confidence" // ConditionSource tests the campaign or provider the event came from. ConditionSource = "source" // ConditionHasContact tests whether the event resolved a contact email. ConditionHasContact = "has_contact" )
Condition kinds accepted in AutomationCondition.Field.
const ( ConditionOpEquals = "equals" ConditionOpNotEquals = "not_equals" ConditionOpContains = "contains" ConditionOpGte = "gte" ConditionOpLte = "lte" ConditionOpExists = "exists" ConditionOpIsTrue = "is_true" ConditionOpChance = "chance" )
Operators accepted in AutomationCondition.Operator.
const ( NodeStatusSuccess = "success" NodeStatusError = "error" NodeStatusSkipped = "skipped" NodeStatusBranchTrue = "branch_true" NodeStatusBranchFalse = "branch_false" )
Per-node outcomes returned in AutomationNodeResult.Status.
const ( AutomationRunning = "running" AutomationSuccess = "success" AutomationError = "error" )
Automation run outcomes returned in AutomationRun.Status.
const ( EdgeWhenTrue = "true" EdgeWhenFalse = "false" // EdgeWhenError is the path taken when the source action fails. EdgeWhenError = "error" // EdgeCasePrefix prefixes an AI switch case name, as in "label:interested". EdgeCasePrefix = "label:" )
Branch labels for AutomationEdge.When. A condition node's two outgoing edges must be EdgeWhenTrue and EdgeWhenFalse. An action node takes a plain edge (empty When) plus an optional EdgeWhenError branch, and an ActionAISwitch node may additionally carry one EdgeCasePrefix edge per configured case. Anything else is rejected when the automation is saved.
const ( ProrationCreate = "create_prorations" ProrationAlwaysInvoice = "always_invoice" ProrationNone = "none" )
Proration behaviors accepted by ChangePlanParams.ProrationBehavior.
const ( // ReferralStatusPending means the invitee signed up but has not converted // yet. ReferralStatusPending = "pending" // ReferralStatusQualified means the conversion counts; the reward is owed. ReferralStatusQualified = "qualified" // ReferralStatusRewarded means the credit has been applied. ReferralStatusRewarded = "rewarded" // ReferralStatusVoid means the reward was withdrawn, for example after a // refund. See [ReferralAttribution.VoidReason]. ReferralStatusVoid = "void" )
Reward states returned in ReferralAttribution.Status.
const ( // DiscountTypePercent takes a percentage off. DiscountTypePercent = "percent" // DiscountTypeFixed takes a fixed amount off. DiscountTypeFixed = "fixed" // DiscountTypeTrialExtension adds trial days instead of reducing a // charge. DiscountTypeTrialExtension = "trial_extension" )
What a discount code grants, in DiscountPreview.Type and DiscountRedemption.Type.
const ( DiscountDurationOnce = "once" DiscountDurationRepeating = "repeating" DiscountDurationForever = "forever" )
How long a money discount keeps applying, in DiscountPreview.Duration.
const ( DiscountRedemptionPending = "pending" DiscountRedemptionApplied = "applied" DiscountRedemptionCanceled = "canceled" )
Redemption states returned in DiscountRedemption.Status.
const ( CampaignStatusDraft = "draft" CampaignStatusScheduled = "scheduled" CampaignStatusActive = "active" CampaignStatusPaused = "paused" // CampaignStatusPausedNoAccounts is set when the campaign loses every // sender, or no sender can send under its settings (a failing SPF/DMARC // domain, a sending-behavior profile with no working days). CampaignStatusPausedNoAccounts = "paused_no_accounts" // CampaignStatusPausedTrialExpired is set when the organization's trial // ends while the campaign is running. CampaignStatusPausedTrialExpired = "paused_trial_expired" // CampaignStatusPausedGuardrail is set when an auto-pause guardrail trips; // [Campaign.GuardrailReason] says which one. CampaignStatusPausedGuardrail = "paused_guardrail" // CampaignStatusPausedUndeliverable is set when address verification has // refused every remaining lead. Re-verify them or mark them deliverable // (POST /contacts/verification) to resume; starting again from this // status is not gated by the list bounce-risk check. CampaignStatusPausedUndeliverable = "paused_undeliverable" CampaignStatusCompleted = "completed" CampaignStatusStopped = "stopped" )
Campaign lifecycle states returned in Campaign.Status.
The server stores draft, active, paused, completed and the paused_* variants. Every paused_* variant is a self-inflicted pause with a specific cause and is restartable with CampaignService.Start once the cause is fixed. "Waiting for leads" is not a status: a continuous campaign that has run out of leads stays active and sets Campaign.IdleSince instead.
const ( // CampaignKindSequence is the multi-step default. CampaignKindSequence = "sequence" // CampaignKindOneTime is a single message with no follow-ups. It is a // normal campaign underneath (same pool, caps, suppression and analytics) // but accepts at most one email step and refuses further ones. CampaignKindOneTime = "one_time" )
Campaign kinds returned in Campaign.Kind. The kind is fixed at creation.
const ( // SenderStrategyTags resolves the sending pool from the mailbox tags in // [Campaign.EmailTags]. SenderStrategyTags = "tags" // SenderStrategyExplicit uses the pool managed through // [CampaignService.Senders]. SenderStrategyExplicit = "explicit" )
Sender-selection strategies for Campaign.SenderStrategy.
const ( ESPMatchOff = "off" ESPMatchPrefer = "prefer" ESPMatchStrict = "strict" )
ESP-matching modes for Campaign.ESPMatchMode, which bias sends towards a mailbox on the same provider as the recipient.
const ( // ErrCodeListBounceRisk is returned (400) when the list's projected bounce // rate is too high: above 4% of known-invalid addresses among deliverable // leads, on lists of at least 50. Launch anyway with // [CampaignStartParams.AcknowledgeListRisk]. ErrCodeListBounceRisk = "list_bounce_risk" // ErrCodeLeadsUndeliverable is returned (400) when every remaining lead was // refused by address verification. The campaign is parked at // [CampaignStatusPausedUndeliverable]. ErrCodeLeadsUndeliverable = "leads_undeliverable" // ErrCodeNoLeads is returned (400) when a campaign that has never had a // lead is started with [CampaignUpdateParams.Continuous] off. Add contacts, // or set Continuous so it starts empty and waits for them. A campaign whose // leads have all finished is a different case: it starts and waits, with // [CampaignStatusChange.WaitingForLeads] set. ErrCodeNoLeads = "no_leads" // ErrCodeNoRemainingLeads is returned (400) only to a platform-initiated // restart of a campaign with nothing left to send and Continuous off; the // campaign returns to [CampaignStatusCompleted]. A start you request never // answers this, because it turns Continuous on and waits instead. ErrCodeNoRemainingLeads = "no_remaining_leads" )
Error codes (Error.Code) a CampaignService.Start can refuse with.
const ( // StepKindEmail renders and sends the step's subject and body. StepKindEmail = "email" // StepKindAction runs a side effect described by [Step.Action]. StepKindAction = "action" // StepKindWait delays without sending. StepKindWait = "wait" )
Step kinds returned in Step.Kind.
const ( // VerificationSourceProbe is the built-in check (syntax, MX, SMTP probe). VerificationSourceProbe = "probe" // VerificationSourceProvider is a connected verification service. VerificationSourceProvider = "provider" // VerificationSourceImported is a verdict that arrived with the contact, // through [ContactInput.VerificationStatus] or an import column. The // background check leaves it alone until it ages out. VerificationSourceImported = "imported" // VerificationSourceManual is a verdict a member set through // [ContactService.RequestVerification]. It is never re-checked // automatically. VerificationSourceManual = "manual" )
Who produced a contact's verification verdict, returned in Contact.VerificationSource. Empty means the address was never checked.
const ( VerificationSubStatusCatchAll = "catch_all" VerificationSubStatusDisposable = "disposable" VerificationSubStatusRole = "role" VerificationSubStatusSpamtrap = "spamtrap" VerificationSubStatusMailboxFull = "mailbox_full" VerificationSubStatusNoMX = "no_mx" VerificationSubStatusSyntax = "syntax" VerificationSubStatusUndisclosed = "undisclosed" )
Refinements of a verification status, returned in Contact.VerificationSubStatus. Empty when the status needs no qualifier.
const ( // VerificationProviderBuiltin is Warmbly's own check. VerificationProviderBuiltin = "builtin" // VerificationProviderWarmbly names Warmbly's vocabulary (valid, risky, // invalid, unknown) when supplying a verdict you already hold. VerificationProviderWarmbly = "warmbly" VerificationProviderMillionVerifier = "millionverifier" VerificationProviderZeroBounce = "zerobounce" VerificationProviderNeverBounce = "neverbounce" VerificationProviderBouncer = "bouncer" VerificationProviderKickbox = "kickbox" VerificationProviderEmailable = "emailable" VerificationProviderDebounce = "debounce" VerificationProviderClearout = "clearout" VerificationProviderEmailListVerify = "emaillistverify" )
Verification vocabularies accepted in ContactInput.VerificationProvider and ImportColumnMapping.VerificationProvider, plus the two verifiers a workspace can run (ContactVerificationOverview.Provider).
const ( // LeadStatusPending means the contact is enrolled but nothing has been sent. LeadStatusPending = "pending" // LeadStatusActive means some but not all steps have been sent. LeadStatusActive = "active" // LeadStatusCompleted means every step was sent with no reply. LeadStatusCompleted = "completed" // LeadStatusReplied is terminal: the contact replied. LeadStatusReplied = "replied" // LeadStatusBounced is terminal: a send hard-bounced. LeadStatusBounced = "bounced" // LeadStatusFailed is terminal: the mailbox could not send a step after // every retry. [ContactCampaignProgress.FailureReason] says why. LeadStatusFailed = "failed" // LeadStatusUnsubscribed is terminal: the contact is suppressed. LeadStatusUnsubscribed = "unsubscribed" // LeadStatusUndeliverable is a lead the campaign skips because address // verification refused it (invalid, or risky with the campaign's risky // toggle off). Re-verifying or marking it deliverable // ([ContactService.RequestVerification]) puts it back in the queue. LeadStatusUndeliverable = "undeliverable" )
Derived lead states returned in ContactCampaignProgress.Status, ContactCampaignState.LeadStatus and accepted by ContactSearchParams.LeadStatus. Highest priority first: unsubscribed, bounced, replied, failed, completed, active, undeliverable, pending.
const ( LeadEngagementOpened = "opened" LeadEngagementNotOpened = "not_opened" LeadEngagementClicked = "clicked" LeadEngagementNotClicked = "not_clicked" LeadEngagementReplied = "replied" LeadEngagementNotReplied = "not_replied" LeadEngagementBounced = "bounced" )
Engagement filters accepted by ContactSearchParams.Engagement. Each is a predicate over the contact's progress in one campaign; the Not* forms match only leads that were sent at least one step, so a lead never emailed is neither opened nor not-opened. Opens are human opens only.
const ( VerificationEvidenceDelivered = "delivered" VerificationEvidenceOpened = "opened" VerificationEvidenceClicked = "clicked" VerificationEvidenceReplied = "replied" VerificationEvidenceAutoReplied = "auto_replied" VerificationEvidenceBouncedRecipient = "bounced_recipient" VerificationEvidenceBouncedOther = "bounced_other" )
Kinds of observation in ContactVerificationEvidence.Kind.
const ( // ContactSourceUnknown is the honest value for contacts created before // attribution existed. ContactSourceUnknown = "unknown" // ContactSourceManual is a contact added by hand in the dashboard. ContactSourceManual = "manual" // ContactSourceCampaign is a contact added from a campaign's Leads tab. ContactSourceCampaign = "campaign" // ContactSourceImport is a file import; the detail is the file name. ContactSourceImport = "import" // ContactSourceSheetSync is a Google Sheets sync; the detail is the sheet. ContactSourceSheetSync = "sheet_sync" // ContactSourceAPI is an API-key request; the detail is the key's name. ContactSourceAPI = "api" // ContactSourceAIAssistant is a contact the AI assistant created. ContactSourceAIAssistant = "ai_assistant" // ContactSourceForm is a hosted form submission; the detail is the form. ContactSourceForm = "form" // ContactSourceAutomation is an automation's "create or update contact" // action; the detail is the automation's name. ContactSourceAutomation = "automation" )
Where a contact first came from, returned in ContactDetail.Source and on TimelineContactCreated events. It never changes after creation.
const ( TimelineEmailSent = "email_sent" TimelineEmailOpened = "email_opened" TimelineEmailClicked = "email_clicked" TimelineEmailReplied = "email_replied" TimelineEmailBounced = "email_bounced" TimelineReplyReceived = "reply_received" TimelineDeliverability = "deliverability" TimelineSuppressed = "suppressed" TimelineNote = "note" TimelineMeetingBooked = "meeting_booked" TimelineMeetingRescheduled = "meeting_rescheduled" TimelineMeetingCanceled = "meeting_canceled" // Lifecycle events. TimelineContactCreated carries Source and // SourceDetail; the campaign and category events carry the name as it was // at the time, so a later rename does not rewrite history. TimelineContactCreated = "contact_created" TimelineCampaignAdded = "campaign_added" TimelineCampaignRemoved = "campaign_removed" TimelineCategoryAdded = "category_added" TimelineCategoryRemoved = "category_removed" // TimelineFormSubmitted carries FormID and FormName. TimelineFormSubmitted = "form_submitted" // TimelinePageHit is a page view on your own site by a browser tied to the // contact through an email-link ticket. Subject is the page title (or its // path) and PageHit carries the full view. TimelinePageHit = "page_hit" )
Timeline event types returned in TimelineEvent.Type.
const ( // MachineReasonPrefetch is a mail privacy proxy or security gateway. MachineReasonPrefetch = "prefetch" // MachineReasonInstant is a fetch within ten seconds of the send. MachineReasonInstant = "instant" // MachineReasonBurst is several links followed within seconds (clicks only). MachineReasonBurst = "burst" )
Why an open or click was classified as automated, returned in TimelineEvent.MachineReason.
const ( ActivityEmailSent = "email_sent" ActivityEmailOpened = "email_opened" ActivityEmailClicked = "email_clicked" ActivityEmailReplied = "email_replied" ActivityEmailBounced = "email_bounced" ActivityNoteAdded = "note_added" ActivityNoteUpdated = "note_updated" ActivityDealCreated = "deal_created" ActivityDealStageChange = "deal_stage_changed" ActivityDealWon = "deal_won" ActivityDealLost = "deal_lost" ActivityTaskCreated = "task_created" ActivityTaskCompleted = "task_completed" ActivityContactCreated = "contact_created" ActivityContactUpdated = "contact_updated" ActivityFormSubmitted = "form_submitted" ActivityCampaignAdded = "campaign_added" ActivityCampaignRemoved = "campaign_removed" ActivityCategoryAdded = "category_added" ActivityCategoryRemoved = "category_removed" )
Contact activity types returned in ContactActivity.ActivityType.
const ( FilterEqual = "equal" FilterStartsWith = "starts_with" FilterEndsWith = "ends_with" FilterContains = "contains" )
Custom-field match modes for ContactFieldFilter.Type.
const ( // FieldOpAdd sets the field only where it is currently absent. FieldOpAdd = "ADD" // FieldOpEdit overwrites the field's value. FieldOpEdit = "EDIT" // FieldOpDelete removes the field. FieldOpDelete = "DELETE" // FieldOpRename renames the key to Value, keeping each contact's value. FieldOpRename = "RENAME" )
Bulk custom-field operations for ContactFieldEdit.Type.
const ( // VerificationActionVerify queues a fresh check. Each contact updates as // its verdict lands. VerificationActionVerify = "verify" // VerificationActionMarkDeliverable records a manual "valid" verdict and // resumes any campaign of the workspace paused for verification. VerificationActionMarkDeliverable = "mark_deliverable" // VerificationActionMarkUndeliverable records a manual "invalid" verdict. VerificationActionMarkUndeliverable = "mark_undeliverable" )
Actions accepted by ContactVerificationParams.Action.
const ( // NextActionDue carries ScheduledAt, the slot the scheduler would give the // step on its next pass. Leads ahead in the queue can still push it later. NextActionDue = "due" // NextActionWaiting carries NotBefore and a Constraint. NextActionWaiting = "waiting" // NextActionPaused and NextActionBlocked carry only the Constraint. NextActionPaused = "paused" NextActionBlocked = "blocked" )
How firm a ContactNextAction's timing is, in ContactNextAction.State.
const ( ExportFormatCSV = "csv" ExportFormatXLSX = "xlsx" ExportFormatJSON = "json" )
Export formats accepted by ContactExportParams.Format.
const ( // ExportScopeAll exports every contact in the organization. ExportScopeAll = "all" // ExportScopeFiltered exports whatever [ContactExportParams.Filters] match. ExportScopeFiltered = "filtered" // ExportScopeSelected exports the ids in [ContactExportParams.ContactIDs]. ExportScopeSelected = "selected" )
Export scopes accepted by ContactExportParams.Scope.
const ( ExportFieldID = "id" ExportFieldEmail = "email" ExportFieldFirstName = "first_name" ExportFieldLastName = "last_name" ExportFieldCompany = "company" ExportFieldPhone = "phone" ExportFieldSubscribed = "subscribed" ExportFieldCategories = "categories" ExportFieldCampaigns = "campaigns" ExportFieldCreatedAt = "created_at" ExportFieldUpdatedAt = "updated_at" // The lead columns are the contact's engagement inside the one campaign // named in [ContactExportParams.Filters].CampaignIDs. They are blank when // the filters do not name exactly one campaign. ExportFieldLeadStatus = "lead_status" ExportFieldLeadOpened = "lead_opened" ExportFieldLeadClicked = "lead_clicked" ExportFieldLeadReplied = "lead_replied" )
Built-in export column identifiers. A custom field is addressed as "custom:<key>".
const ( ImportTargetIgnore = "ignore" ImportTargetEmail = "email" ImportTargetFirstName = "first_name" ImportTargetLastName = "last_name" ImportTargetCompany = "company" ImportTargetPhone = "phone" ImportTargetSubscribed = "subscribed" ImportTargetCategories = "categories" // ImportTargetVerificationStatus reads a verdict column written by Warmbly // or another verification service. A cell nobody recognizes leaves that // contact unverified rather than failing the row. ImportTargetVerificationStatus = "verification_status" // ImportTargetCustom routes the column into a custom field named by // [ImportColumnMapping.CustomKey]. The older "custom:<key>" spelling is // still accepted. ImportTargetCustom = "custom" )
Where an imported column lands, for ImportColumnMapping.Target.
const ( ImportDedupSkip = "skip" ImportDedupUpdate = "update" ImportDedupCreateDuplicate = "create_duplicate" )
How an import treats a row whose address already exists, for ContactImportParams.Dedup.
const ( ResearchQueued = "queued" ResearchRunning = "running" ResearchSucceeded = "succeeded" ResearchFailed = "failed" ResearchNothingFound = "nothing_found" )
Research run states returned in ResearchRun.Status. ResearchNothingFound is a billable success: the agent looked and honestly found nothing.
const ( DealStatusOpen = "open" DealStatusWon = "won" DealStatusLost = "lost" )
Deal states returned in Deal.Status.
const ( TaskPriorityLow = "low" TaskPriorityMedium = "medium" TaskPriorityHigh = "high" TaskPriorityUrgent = "urgent" )
CRM task priorities returned in CRMTask.Priority.
const ( TaskStatusPending = "pending" TaskStatusInProgress = "in_progress" TaskStatusCompleted = "completed" TaskStatusCancelled = "cancelled" //nolint:misspell // wire value: the API sends "cancelled" here )
CRM task states returned in CRMTask.Status.
const ( ProviderGmail = "gmail" ProviderOutlook = "outlook" ProviderSMTPIMAP = "smtp_imap" )
Mailbox provider values returned in Email.Provider.
const ( MailboxStatusActive = "active" MailboxStatusInactive = "inactive" MailboxStatusRevoked = "revoked" )
Mailbox connection states returned in Email.Status.
const ( // AuthStateUnknown means the domain has not been checked yet, the DNS // lookup could not complete, or the domain is special-use and cannot // resolve. It never gates sending. AuthStateUnknown = "unknown" // AuthStatePassing means SPF and DMARC are both published. AuthStatePassing = "passing" // AuthStateFailing means SPF or DMARC is missing. A domain that stays // failing past the instance grace period (72 hours by default, measured // from [Email.AuthFailingSince]) stops cold sending and warmup from every // mailbox on it. AuthStateFailing = "failing" )
Sending-domain authentication states returned in Email.AuthState.
const ( // ErrCodeMailboxAllowanceReached is the 403 returned by every connect path // once the workspace's mailbox allowance is full. See // [EmailService.Allowance]. ErrCodeMailboxAllowanceReached = "mailbox_allowance_reached" // ErrCodeMailboxWorkerUnreachable is the 503 returned by // [EmailService.Delete] when the worker syncing the mailbox could not be // told to drop it. Nothing was removed; retry in a moment. ErrCodeMailboxWorkerUnreachable = "mailbox_worker_unreachable" )
Error codes carried in Error.Code by mailbox operations.
const ( // SendModeInstant enqueues the message immediately. SendModeInstant = "instant" // SendModeSmart places the message in the next gap in the mailbox's // sending schedule. It follows the mailbox's workday when sending behavior // is enabled but is never charged against the cold-send budgets. SendModeSmart = "smart" // SendModeScheduled sends at [SendEmailParams.ScheduledAt]. SendModeScheduled = "scheduled" )
Send modes accepted by SendEmailParams.SendMode.
const ( // TrackingStatusVerified: the subdomain resolves to the tracking host and // new sends use it. TrackingStatusVerified = "verified" // TrackingStatusUnset: no custom domain is configured. TrackingStatusUnset = "unset" // TrackingStatusNoTarget: this install has no tracking host, so there is // nothing to point at and nothing can verify. TrackingStatusNoTarget = "no_target" // TrackingStatusNotFound: the name does not exist yet. The record has not // been added or has not propagated (usually minutes, up to an hour). TrackingStatusNotFound = "not_found" // TrackingStatusWrongTarget: the record exists but points at another // host; [TrackingDomainStatus.Observed] says which. TrackingStatusWrongTarget = "wrong_target" // TrackingStatusLookupError: DNS could not answer. A transient failure // never revokes an already verified domain. TrackingStatusLookupError = "lookup_error" // TrackingStatusPending: stored state that has not been re-resolved, as // reported by the read-only [EmailService.GetTrackingDomain]. TrackingStatusPending = "pending" )
Machine-readable verdicts returned in TrackingDomainStatus.Status.
const ( VerifyStatusValid = "valid" VerifyStatusRisky = "risky" VerifyStatusInvalid = "invalid" VerifyStatusUnknown = "unknown" )
Address verification outcomes returned in VerifyResult.Status.
const ( VerifySubStatusCatchAll = "catch_all" VerifySubStatusDisposable = "disposable" VerifySubStatusRole = "role" VerifySubStatusSpamTrap = "spamtrap" VerifySubStatusMailboxFull = "mailbox_full" VerifySubStatusNoMX = "no_mx" VerifySubStatusSyntax = "syntax" // VerifySubStatusUndisclosed marks a provider (Microsoft, Yahoo) that // answers every RCPT the same way, so a probe cannot judge the mailbox. VerifySubStatusUndisclosed = "undisclosed" )
Reason classes returned in VerifyResult.SubStatus when the verifier can name one.
const ( // MailSecurityTLS is implicit TLS: encrypted from the first byte. The // convention for SMTP 465 and IMAP 993. MailSecurityTLS = "tls" // MailSecurityStartTLS is a plaintext greeting upgraded in place with // STARTTLS. The convention for SMTP 587, 25 and 2525, and IMAP 143. MailSecurityStartTLS = "starttls" )
Connection security modes accepted in MailboxCredentials.Security. TLS is mandatory either way; the difference is whether it is negotiated before the protocol greeting or upgraded in-band after it.
const ( // MailboxBulkConnected: the credentials were validated and the mailbox // connected. MailboxBulkConnected = "connected" // MailboxBulkSkipped: the mailbox was already connected, so re-sending a // batch is safe. MailboxBulkSkipped = "skipped" // MailboxBulkFailed: the row was refused; [MailboxBulkRow.Code] says why. MailboxBulkFailed = "failed" )
Per-row outcomes returned in MailboxBulkRow.Status.
const ( // MailboxAllowanceUnlimited: no billing provider, or a plan with no daily // send cap. Allowance is nil. MailboxAllowanceUnlimited = "unlimited" // MailboxAllowanceFree: an unsubscribed workspace's fixed limit. MailboxAllowanceFree = "free" // MailboxAllowanceOverride: an operator-approved limit-increase request. MailboxAllowanceOverride = "override" // MailboxAllowancePlan: the plan carries an explicit mailbox limit. MailboxAllowancePlan = "plan" // MailboxAllowanceFairUse: the plan's daily sends divided by // [MailboxAllowance.SendsPerMailbox]. MailboxAllowanceFairUse = "fair_use" )
Sources of a workspace's mailbox allowance, returned in MailboxAllowance.Basis.
const ( // SendLifecycleActive: in campaign rotation. The default. SendLifecycleActive = "active" // SendLifecycleResting: pulled out of campaign rotation to recover on // warmup traffic alone. Entered automatically when warmup health reaches // "throttled" or worse and left on its own once the mailbox has been // healthy for three days, or earlier through [EmailService.Release]. SendLifecycleResting = "resting" // SendLifecycleReserve: held back deliberately by the owner through // [EmailService.Hold]. Never entered or left automatically. SendLifecycleReserve = "reserve" )
Cold-rotation states returned in SendLifecycleState.State.
const ( // SyncBackfillPending: the mailbox is loaded but the import has not run. SyncBackfillPending = "pending" // SyncBackfillRunning: the import is walking history, newest first, and // may be paced. SyncBackfillRunning = "running" // SyncBackfillComplete: the window is exhausted or the cap was reached. SyncBackfillComplete = "complete" )
Backfill stages returned in MailboxSyncState.BackfillStatus.
const ( SyncThrottleBurst = "burst" SyncThrottleHourly = "hourly" SyncThrottleDaily = "daily" SyncThrottleOrgDaily = "org_daily" SyncThrottlePriorityFull = "priority_daily" )
Exhausted budgets named in MailboxSyncState.ThrottleReason.
const ( BehaviorMonday = 1 << 0 BehaviorTuesday = 1 << 1 BehaviorWednesday = 1 << 2 BehaviorThursday = 1 << 3 BehaviorFriday = 1 << 4 BehaviorSaturday = 1 << 5 BehaviorSunday = 1 << 6 // BehaviorWeekdays is Monday to Friday, the default. BehaviorWeekdays = BehaviorMonday | BehaviorTuesday | BehaviorWednesday | BehaviorThursday | BehaviorFriday // BehaviorEveryDay is all seven days. BehaviorEveryDay = BehaviorWeekdays | BehaviorSaturday | BehaviorSunday )
Weekday bits for SendingBehavior.Weekdays. The mask is Monday-indexed (bit 0 = Monday), matching the campaign week grid.
const ( // ErrCodeBadRequest is the generic 400: malformed JSON, a missing required // field, a value out of range. ErrCodeBadRequest = "bad_request" // would not accept. ErrCodeUnauthorized = "unauthorized" // ErrCodeForbidden is the generic 403: authenticated, but the credential // lacks the permission (or the IP is outside the key's allowlist). ErrCodeForbidden = "forbidden" // ErrCodeNotFound is the generic 404. It is also what a resource in // another workspace returns, so it does not prove non-existence. ErrCodeNotFound = "not_found" // ErrCodeConflict is the generic 409: the resource already exists, or a // unique value collided. ErrCodeConflict = "conflict" // ErrCodeUnprocessable is the generic 422: the request parsed but failed // validation. ErrCodeUnprocessable = "unprocessable" // ErrCodeRateLimitExceeded is the 429 for the per-key request rate. Honor // [Error.RetryAfter]; the client's own retry does. ErrCodeRateLimitExceeded = "rate_limit_exceeded" // ErrCodeInternalError is the generic 500. Retry once, then quote // [Error.RequestID] to support. ErrCodeInternalError = "internal_error" // ErrCodeNotImplemented is the 501 for a feature this deployment does not // build in. ErrCodeNotImplemented = "not_implemented" // transient one of the three 503 codes. ErrCodeServiceUnavailable = "service_unavailable" // ErrCodeInsufficientCredits is the 402 every AI action returns once the // workspace's credit balance is spent. Top up or wait for the monthly // allowance; retrying changes nothing. ErrCodeInsufficientCredits = "insufficient_credits" // ErrCodeUsageCapExceeded is a 429 from the AI endpoints: a short-term // usage cap, not the request-rate limiter. Unlike // [ErrCodeInsufficientCredits] it clears on its own, so retry later. ErrCodeUsageCapExceeded = "usage_cap_exceeded" // ErrCodeNoOrganization is a 400 raised when a request needs a workspace // and the session has none selected. API keys always carry theirs, so this // is a dashboard-session condition: every entitlement, limit and // suppression rule is workspace-scoped, and a write that would run // unscoped is refused rather than run without those checks. ErrCodeNoOrganization = "no_organization" // ErrCodeStorageLimitReached is the 400 from campaign attachment uploads // (and from duplicating a campaign that has them) when the workspace's // total attachment storage would pass its quota. The check and the write // happen under one lock, so nothing was stored. GET // organization/current/limits reports the quota and what is used. ErrCodeStorageLimitReached = "storage_limit_reached" // ErrCodeMailboxProviderNotConfigured is a 503 that is not transient: // the deployment has no OAuth client for the mailbox provider the request // named. Self-hosted only. Set the provider's credentials, or connect the // mailbox over SMTP and IMAP instead. ErrCodeMailboxProviderNotConfigured = "mailbox_provider_not_configured" // ErrCodeInvalidLeadStatus and ErrCodeInvalidEngagement are 400s from the // contact search and export endpoints for a filter value outside the // documented set. ErrCodeInvalidLeadStatus = "invalid_lead_status" ErrCodeInvalidEngagement = "invalid_engagement" // ErrCodeLeadFilterRequiresCampaign is the 400 for setting a lead status // or engagement filter without exactly one campaign id. Both describe a // contact's standing inside one campaign, so they are meaningless without // it. ErrCodeLeadFilterRequiresCampaign = "lead_filter_requires_campaign" // ErrCodeUnknownVerificationStatus and ErrCodeUnknownVerificationProvider // are 400s raised when a stored contact carries a verification status or // provider this platform version cannot read — a row written by a newer // deployment, or by a service that has since been removed. ErrCodeUnknownVerificationStatus = "unknown_verification_status" ErrCodeUnknownVerificationProvider = "unknown_verification_provider" // ErrCodeInvalidAction is the 400 from the contact verification endpoint // for an action other than verify, mark_deliverable or // mark_undeliverable. ErrCodeInvalidAction = "invalid_action" // ErrCodeNoContacts is the 400 from the contact verification endpoint when // the selection resolved to nothing: no explicit contacts, and no campaign // with refused leads. ErrCodeNoContacts = "no_contacts" // ErrCodeRegistrationInviteOnly and ErrCodeRegistrationClosed are 403s // describing a deployment's signup policy. They never reveal whether an // address already has an account. ErrCodeRegistrationInviteOnly = "registration_invite_only" ErrCodeRegistrationClosed = "registration_closed" // ErrCodeInvitationInvalid is the 403 for an invitation that is expired, // canceled, already used, or was issued for a different address. ErrCodeInvitationInvalid = "invitation_invalid" // ErrCodeSetupTokenInvalid is the 401 from the first-run claim endpoint // for a setup link that is invalid, already used or expired. ErrCodeSetupTokenInvalid = "setup_token_invalid" // ErrCodeSetupAlreadyComplete is the 403 for claiming an instance that // already has an account. ErrCodeSetupAlreadyComplete = "setup_already_complete" // ErrCodeSSOWrongBrowser is the 401 from the SSO exchange when the handoff // code arrives without the binding secret the browser that started the // sign-in was given. The handoff is deliberately non-transferable: a // forwarded sign-in link cannot sign the recipient in. ErrCodeSSOWrongBrowser = "sso_wrong_browser" )
Stable machine-readable values of the "code" field in the error envelope, for callers that need to branch on the specific condition rather than the HTTP status. Match them with Error.HasCode.
Every response carries one: an endpoint that has nothing more specific to say answers with the generic code for its status class. A few codes live with the service they belong to instead of here — ErrCodeMailboxAllowanceReached, ErrCodeMailboxWorkerUnreachable, ErrCodeListBounceRisk and ErrCodeLeadsUndeliverable.
const ( FormStatusDraft = "draft" FormStatusPublished = "published" FormStatusArchived = "archived" )
Form lifecycle values returned in Form.Status. Only a published form renders and accepts submissions; a draft or archived form's page answers not found, while its data is kept.
const ( FormFieldTypeText = "text" FormFieldTypeEmail = "email" FormFieldTypePhone = "phone" FormFieldTypeTextarea = "textarea" FormFieldTypeNumber = "number" FormFieldTypeSelect = "select" FormFieldTypeRadio = "radio" FormFieldTypeCheckboxes = "checkboxes" FormFieldTypeCheckbox = "checkbox" FormFieldTypeDate = "date" // FormFieldTypeHidden submits the constant in [FormField.Value] without // rendering anything; use it to tag which page or campaign a form sits on. FormFieldTypeHidden = "hidden" FormFieldTypeHeading = "heading" FormFieldTypeParagraph = "paragraph" FormFieldTypeDivider = "divider" // FormFieldTypePageBreak starts a new page; its label is the page title // shown on the form and in the analytics funnel. FormFieldTypePageBreak = "page_break" )
Block types for FormField.Type. Input types collect a value on submit; heading, paragraph, divider and page_break only render.
const ( FormMapToFirstName = "first_name" FormMapToLastName = "last_name" FormMapToEmail = "email" FormMapToCompany = "company" FormMapToPhone = "phone" )
Contact columns a field may fill through FormField.MapTo. At most one field may map to each column, and an email-type field always maps to FormMapToEmail.
const ( FormFieldWidthFull = "full" FormFieldWidthHalf = "half" )
Column widths for FormField.Width. Two half-width fields share a row.
const ( FormLayoutCard = "card" FormLayoutWide = "wide" FormLayoutSplit = "split" )
Layouts for FormDesign.Layout: a centered card, fields directly on the page background, or a cover panel beside the form.
const ( FormModeClassic = "classic" FormModeFocus = "focus" )
Modes for FormDesign.Mode: every field of a page at once, or one question per screen.
const ( FormFontSystem = "system" FormFontInter = "inter" FormFontSerif = "serif" FormFontMono = "mono" FormFontManrope = "manrope" FormFontSora = "sora" FormFontFraunces = "fraunces" FormFontSpaceGrotesk = "space-grotesk" )
Font families accepted in FormDesign.FontFamily.
const ( FormSizeSmall = "sm" FormSizeMedium = "md" FormSizeLarge = "lg" )
Sizes shared by FormDesign.ButtonSize and FormDesign.LogoSize.
const ( FormSpacingCompact = "compact" FormSpacingNormal = "normal" FormSpacingRelaxed = "relaxed" )
Vertical rhythm values for FormDesign.Spacing.
const ( FormAlignLeft = "left" FormAlignCenter = "center" FormAlignBetween = "between" )
Alignment values. FormDesign.Align takes left or center; FormDesign.HeaderAlign also takes between (logo one side, title the other).
const ( FormHeaderPlacementPage = "page" FormHeaderPlacementInline = "inline" )
Placements for FormDesign.HeaderPlacement: edge to edge above everything, or on the form surface above the fields.
const ( FormLogoPositionCard = "card" FormLogoPositionPage = "page" )
Positions for FormDesign.LogoPosition on the card layout: on the card, or above it on the page background.
const ( FormBackgroundSizeCover = "cover" FormBackgroundSizeContain = "contain" FormBackgroundSizeTile = "tile" )
Fits for FormDesign.BackgroundSize, how the uploaded background image covers the page.
const ( FormAssetLogo = "logo" FormAssetCover = "cover" FormAssetBackground = "background" )
Asset kinds for FormService.UploadAsset and FormService.DeleteAsset. Every asset must be a PNG or JPG. A logo is capped at 1 MB and 1024px on its longest side; a cover (the split layout's side panel) and a background (behind the whole page) at 4 MB and 2560px.
const ( FormStatsRange7Days = "7d" FormStatsRange30Days = "30d" FormStatsRange90Days = "90d" )
Windows accepted by FormService.Stats. Funnel events are kept for 180 days, so 90 days is the widest window the server offers.
const ( // FormsDomainStatusVerified means the CNAME resolves to the forms host. FormsDomainStatusVerified = "verified" // FormsDomainStatusPending is reported by [FormService.Domain] for a // stored domain that has not verified yet; it is a read of stored state, // not a DNS verdict. FormsDomainStatusPending = "pending" // FormsDomainStatusUnset means no custom domain is configured. FormsDomainStatusUnset = "unset" // FormsDomainStatusNoTarget means this install has no forms host, so // there is nothing to point a record at (an operator problem). FormsDomainStatusNoTarget = "no_target" // FormsDomainStatusNotFound means DNS returned no record for the domain. FormsDomainStatusNotFound = "not_found" // FormsDomainStatusWrongTarget means the record exists but points // somewhere other than [FormsDomainStatus.CNAMETarget]; compare // [FormsDomainStatus.Observed] to spot the typo. FormsDomainStatusWrongTarget = "wrong_target" // FormsDomainStatusLookupError means the lookup itself failed // (timeout, SERVFAIL); retry rather than treating it as misconfigured. FormsDomainStatusLookupError = "lookup_error" )
Verification outcomes reported in FormsDomainStatus.Status. Only FormsDomainStatusVerified puts form links on the custom domain; every other state leaves them on the shared host, so a half-configured domain never breaks a form.
const ( ProviderHubSpot = "hubspot" ProviderSalesforce = "salesforce" ProviderPipedrive = "pipedrive" ProviderClose = "close" ProviderZapier = "zapier" ProviderMake = "make" ProviderN8N = "n8n" ProviderSlack = "slack" ProviderDiscord = "discord" ProviderCalendly = "calendly" ProviderCalCom = "cal_com" ProviderGoogleSheets = "google_sheets" // ProviderMillionVerifier is a pay-as-you-go address verifier connected // by API key. While it has credits it replaces the built-in check for // every contact you import; when they run out the built-in check takes // over. The key is validated against the provider before it is stored, so // a mistyped key fails [IntegrationService.Connect] rather than silently // leaving every contact on the built-in check. ProviderMillionVerifier = "millionverifier" )
Providers available in the integration catalog.
const ( ConnectionPending = "pending" ConnectionAuthorizing = "authorizing" ConnectionConnected = "connected" ConnectionDegraded = "degraded" ConnectionReauthRequired = "reauth_required" ConnectionDisconnected = "disconnected" )
Connection states returned in IntegrationConnection.Status.
const ( SyncPush = "push" SyncPull = "pull" SyncBoth = "both" )
Data-flow directions for IntegrationConnection.SyncDirection.
const ( MeetingBooked = "booked" MeetingRescheduled = "rescheduled" MeetingCanceled = "canceled" MeetingCompleted = "completed" MeetingNoShow = "no_show" )
Meeting lifecycle states returned in Meeting.Status.
const ( MeetingsUpcoming = "upcoming" MeetingsPast = "past" )
Meeting timeframes accepted by MeetingListParams.Timeframe.
const ( // LeadSyncIdle means never synced, or the last sync succeeded. LeadSyncIdle = "idle" // LeadSyncSyncing means a sync is in flight. LeadSyncSyncing = "syncing" // LeadSyncError means the last sync failed; see // [LeadSyncSource.LastError]. LeadSyncError = "error" )
Source states returned in LeadSyncSource.Status.
const ( AuthTypeAPIKey = "api_key" AuthTypeOAuth = "oauth" AuthTypeJWT = "jwt" )
Authentication types returned in Identity.AuthType.
const ( DurationMonth = "month" DurationYear = "year" )
Billing periods returned in Plan.Duration.
const ( OAuthAppActive = "active" OAuthAppInactive = "inactive" )
OAuth application states returned in OAuthApp.Status.
const ( // OrgPermManageTeam allows inviting and removing members. OrgPermManageTeam uint16 = 1 << iota // OrgPermManageBilling allows viewing invoices and changing plans. OrgPermManageBilling // OrgPermManageCampaigns allows creating and editing campaigns. OrgPermManageCampaigns // OrgPermManageContacts allows creating and editing contacts. OrgPermManageContacts // OrgPermManageEmails allows connecting and editing mailboxes. OrgPermManageEmails // OrgPermViewAnalytics allows viewing reports. OrgPermViewAnalytics // OrgPermSendCampaigns allows starting campaigns, which sends real mail. OrgPermSendCampaigns // OrgPermAccessUnibox allows using the unified inbox. OrgPermAccessUnibox // OrgPermManageSequences allows creating and editing sequence steps. OrgPermManageSequences // OrgPermManageSettings allows changing organization settings. OrgPermManageSettings // OrgPermViewCampaigns grants read-only campaign access. OrgPermViewCampaigns // OrgPermViewContacts grants read-only contact access. OrgPermViewContacts // OrgPermTransferOwnership allows handing the workspace to another member. OrgPermTransferOwnership // OrgPermManageAPIKeys allows managing API keys and OAuth applications. OrgPermManageAPIKeys // OrgPermUseIntegrations allows operating connected integrations — pushing // records, running automations — without granting full settings access. OrgPermUseIntegrations // OrgPermUseAI allows using the AI features, which spend the shared credit // balance. OrgPermUseAI )
Organization permission bits. A member's effective grant is the bitwise OR across their assigned roles, which is what travels in Member.Permissions and Role.Permissions.
These gate a human session and are distinct from the API key scopes (the Perm* constants in apikeys.go).
const ( RoleOwner = "owner" RoleAdmin = "admin" RoleManager = "manager" RoleViewer = "viewer" )
Built-in role names returned in Member.Role.
const ( // OrgRiskTrusted is the default: nothing is restricted. OrgRiskTrusted = "trusted" // OrgRiskWatch changes nothing the workspace can feel; evidence is // accumulating. OrgRiskWatch = "watch" // OrgRiskRestricted lowers send caps and confines warmup to the free // pool. OrgRiskRestricted = "restricted" // OrgRiskSuspended stops sending entirely, pending review. OrgRiskSuspended = "suspended" )
Sending postures returned in OrgRisk.State.
const ( DeletionStatusPending = "pending" DeletionStatusExecuting = "executing" DeletionStatusCompleted = "completed" DeletionStatusCancelled = "cancelled" //nolint:misspell // wire value: the API sends "cancelled" here DeletionStatusFailed = "failed" )
Scheduled-deletion states returned in ScheduledDeletion.Status.
const ( OrgTransferQueued = "queued" OrgTransferRunning = "running" OrgTransferCompleted = "completed" OrgTransferFailed = "failed" // OrgTransferExpired is export-only: the archive was deleted after its // retention window and the row survives as history. OrgTransferExpired = "expired" )
Workspace archive job states returned in OrgExportJob.Status and OrgImportJob.Status.
const ( // OrgDataGroupCore is the workspace itself and is always included. OrgDataGroupCore = "core" OrgDataGroupContacts = "contacts" OrgDataGroupCampaigns = "campaigns" OrgDataGroupCRM = "crm" OrgDataGroupAutomations = "automations" OrgDataGroupAI = "ai" OrgDataGroupWarmup = "warmup" OrgDataGroupInbox = "inbox" OrgDataGroupSending = "sending" OrgDataGroupEvents = "events" OrgDataGroupLogs = "logs" // OrgDataGroupBilling is exported but never applied verbatim on import: // the destination instance owns billing. OrgDataGroupBilling = "billing" )
Data groups an archive can carry, in OrgExportParams.Groups, OrgImportParams.Groups and OrgDataGroupInfo.Key. Read the live catalog with OrganizationService.TransferGroups; these are the keys it uses.
const ( // OrgImportSkip keeps the row that is already there. The safe default: an // import never destroys data that was not in the archive. OrgImportSkip = "skip" // OrgImportOverwrite replaces the existing row with the archive's. OrgImportOverwrite = "overwrite" )
What to do with a row the destination already has, in OrgImportParams.ConflictStrategy.
const ( LimitRequestPending = "pending" LimitRequestApproved = "approved" LimitRequestRejected = "rejected" LimitRequestCancelled = "cancelled" //nolint:misspell // wire value: the API sends "cancelled" here )
Limit-request states returned in LimitRequest.Status.
const ( LimitFieldMaxCampaigns = "max_campaigns" LimitFieldMaxActiveCampaigns = "max_active_campaigns" LimitFieldMaxTeamMembers = "max_team_members" LimitFieldMaxEmailAccounts = "max_email_accounts" LimitFieldMaxContacts = "max_contacts" LimitFieldDailyCampaignLimit = "daily_campaign_limit" )
Ceilings a limit increase can be requested for, in LimitRequestParams.Field and LimitRequest.Field.
const ( // UnsubscribeModeInherit is valid only on a campaign: it follows the // organization's [UnsubscribeSettings]. Sent as the organization mode it // is normalized to [UnsubscribeModeText]. UnsubscribeModeInherit = "inherit" // UnsubscribeModeText appends a plain sentence inviting a reply to opt // out. It is the default: it reads as a personal email, and a reply that // asks to stop is detected and honored automatically. UnsubscribeModeText = "text" // UnsubscribeModeLink appends a sentence with a real, signed unsubscribe // link, unique to the recipient and campaign and valid for a year. UnsubscribeModeLink = "link" // UnsubscribeModeOff appends nothing. UnsubscribeModeOff = "off" )
In-body opt-out modes for UnsubscribeSettings.Mode and Campaign.UnsubscribeMode. The List-Unsubscribe header is a separate per-campaign flag (Campaign.UnsubscribeHeader).
const ( DeliverabilityEventBounce = "bounce" DeliverabilityEventComplaint = "complaint" DeliverabilityEventUnsubscribe = "unsubscribe" DeliverabilityEventOpen = "open" DeliverabilityEventClick = "click" DeliverabilityEventReply = "reply" )
Deliverability event types accepted by DeliverabilityEventParams.EventType.
const ( // PoolLinkCodePending is a code nobody has settled yet. PoolLinkCodePending = "pending" // PoolLinkCodeApproved is a code a member approved whose instance has not // yet collected its token. Poll delivers the token exactly once and moves // the code to [PoolLinkCodeClaimed]. PoolLinkCodeApproved = "approved" // PoolLinkCodeClaimed is a spent code: the instance fetched its token. // Polling it again fails with code "pool_link_code_used". PoolLinkCodeClaimed = "claimed" // PoolLinkCodeDenied is a code a member declined. Polling it fails with // code "pool_link_denied". PoolLinkCodeDenied = "denied" )
Lifecycle of one device-code handshake, as reported in PoolLinkCode.Status and PoolLinkPollResult.Status.
const ( // PoolLinkTierFree warms a capped number of linked mailboxes at no cost. PoolLinkTierFree = "free" // PoolLinkTierPaid lifts the mailbox cap; the workspace's regular hosted // plan also counts as paid. PoolLinkTierPaid = "paid" )
Tiers reported in PoolLinkPlan.Tier.
const ( // SegmentMaxConditions is the most conditions one segment may hold. SegmentMaxConditions = 50 // SegmentMaxListValues is the most entries a list condition may hold. SegmentMaxListValues = 200 // SegmentMaxMemberBatch is the most contact IDs one SetMembers or // MemberModes call accepts. SegmentMaxMemberBatch = 1000 // SegmentMaxOverrides caps the Overrides listing. SegmentMaxOverrides = 500 )
Segment limits enforced by the server.
const ( // TemplateIssueWarn is worth fixing but will not sink the message. TemplateIssueWarn = "warn" // TemplateIssueHigh materially risks landing in spam. TemplateIssueHigh = "high" )
Severities returned in TemplateIssue.Severity.
const ( FolderInbox = "inbox" FolderSent = "sent" FolderDrafts = "drafts" FolderArchive = "archive" FolderSpam = "spam" FolderTrash = "trash" )
Canonical mail folders. Every message is filed in exactly one, derived from where the provider placed it at sync time. They are accepted by UniboxListParams.Folder and UniboxService.MarkFolderSeen, and reported in UniboxMessage.Folder and UniboxOverview.Folders.
const ( // DirectionSent matches messages sent from the workspace's own mailboxes. DirectionSent = "sent" // DirectionReceived matches everything else. DirectionReceived = "received" )
Message directions accepted by UniboxListParams.Direction.
const ( AgentDraftPending = "pending" AgentDraftApproved = "approved" AgentDraftDiscarded = "discarded" )
Inbox-agent draft states returned in AgentDraft.Status.
const ( // MatchAny matches every address on that side. MatchAny = "any" // MatchDomain matches an exact domain. MatchDomain = "domain" // MatchTLD matches a top-level domain. MatchTLD = "tld" // MatchProvider matches a mail provider classification, for example // "gmail" or "outlook". MatchProvider = "provider" )
Match modes for the sender and recipient sides of a routing rule.
const ( // WebhookSignatureHeader carries the signature as "t=<unix>,v1=<hex>", // where the hex digest is an HMAC-SHA256 over "<unix>." followed by the raw // request body, keyed by the endpoint's secret. WebhookSignatureHeader = "X-Warmbly-Signature" // WebhookEventHeader carries the delivered event type. WebhookEventHeader = "X-Warmbly-Event" // WebhookEventIDHeader carries the event's id, which is stable across // retries and so is the right key for receiver-side deduplication. WebhookEventIDHeader = "X-Warmbly-Event-Id" // WebhookChallengeHeader is where a receiver echoes the ownership // challenge back. Read the token from the verified [EventEndpointTest] // payload rather than from this header on the request: the header is a // convenience copy an attacker could forge, while the body is signed. WebhookChallengeHeader = "X-Warmbly-Webhook-Challenge" )
Headers set on every webhook delivery.
const ( WebhookCatCampaign = "Campaign" WebhookCatWarmup = "Warmup" WebhookCatDeliverability = "Deliverability" WebhookCatInbox = "Inbox" WebhookCatEmailAccount = "Mailbox" WebhookCatContact = "Contact" WebhookCatCRM = "CRM" WebhookCatAutomation = "Automation" WebhookCatMeeting = "Meeting" WebhookCatTeam = "Team & access" WebhookCatBulk = "Bulk operations" WebhookCatWorkspace = "Workspace" WebhookCatDeveloper = "Developer" )
Event categories used to group WebhookEventDescriptor entries.
const ( // DeliveryPending is queued for its next attempt. DeliveryPending = "pending" // DeliveryInFlight is being attempted right now. DeliveryInFlight = "in_flight" // DeliveryDelivered succeeded. DeliveryDelivered = "delivered" // DeliveryFailed will be retried. DeliveryFailed = "failed" // DeliveryAbandoned exhausted its attempts. DeliveryAbandoned = "abandoned" )
Delivery states returned in WebhookDelivery.Status.
const ( // WebsiteConsentExplicit records nothing until the page calls // warmbly('consent', 'granted'). The default; enforced server-side as // well, so a stale snippet cannot downgrade it. WebsiteConsentExplicit = "explicit" // WebsiteConsentImplicit records on load. The workspace asserts its own // lawful basis by choosing it. WebsiteConsentImplicit = "implicit" )
Consent modes returned in WebsiteTrackingSettings.ConsentMode.
const ( WebsiteLocationNone = "none" WebsiteLocationCountry = "country" WebsiteLocationCity = "city" )
How much IP-derived location is kept, in WebsiteTrackingSettings.LocationPrecision.
const ( WebsiteRetentionMinDays = 7 WebsiteRetentionMaxDays = 365 WebsiteRetentionDefaultDays = 90 )
Bounds for WebsiteTrackingSettings.RetentionDays.
const DefaultWebhookTolerance = 5 * time.Minute
DefaultWebhookTolerance is how far a delivery's signature timestamp may drift from local time before WebhookService.ConstructEvent rejects it.
const MaxAutomationDepth = 5
MaxAutomationDepth is how many automations may run in a chain before the server stops following it.
const MaxSMTPIMAPBulkRows = 50
MaxSMTPIMAPBulkRows is the most rows one EmailService.ConnectSMTPIMAPBulk call accepts.
const OrgPermAll uint16 = 0xFFFF
OrgPermAll is every organization permission, which is what the owner holds.
const SegmentCustomFieldPrefix = "custom."
SegmentCustomFieldPrefix addresses a contact custom field in a condition: "custom.industry" filters on the custom field "industry". Custom fields are text fields. The workspace's current keys are returned by SegmentService.Fields.
const SuppressionMaxEntries = 5000
SuppressionMaxEntries is the most entries one Add call accepts.
const Version = "0.3.1"
Version is the SDK version, reported in the default User-Agent.
Variables ¶
var ( // ErrBadRequest is returned for HTTP 400 responses. ErrBadRequest = &Error{StatusCode: http.StatusBadRequest} // credentials). ErrUnauthorized = &Error{StatusCode: http.StatusUnauthorized} // ErrForbidden is returned for HTTP 403 responses (authenticated but not // permitted). ErrForbidden = &Error{StatusCode: http.StatusForbidden} // ErrNotFound is returned for HTTP 404 responses. ErrNotFound = &Error{StatusCode: http.StatusNotFound} // ErrConflict is returned for HTTP 409 responses. ErrConflict = &Error{StatusCode: http.StatusConflict} // ErrUnprocessable is returned for HTTP 422 responses (validation failed). ErrUnprocessable = &Error{StatusCode: http.StatusUnprocessableEntity} // ErrRateLimited is returned for HTTP 429 responses. ErrRateLimited = &Error{StatusCode: http.StatusTooManyRequests} // ErrServer matches any HTTP 5xx response. ErrServer = &Error{StatusCode: http.StatusInternalServerError} )
Sentinel errors for matching API failures with errors.Is. They carry only a status code; the concrete error returned from a call carries the full body.
var ( // ErrInvalidWebhookSignature is returned when the delivery signature does // not match the computed HMAC. ErrInvalidWebhookSignature = errors.New("warmbly: invalid webhook signature") // ErrWebhookSignatureExpired is returned when the signature is valid but // its timestamp falls outside the tolerance, which defeats replay. ErrWebhookSignatureExpired = errors.New("warmbly: webhook signature timestamp outside tolerance") )
Errors returned when a delivery fails verification.
var DefaultEndpoint = OAuth2Endpoint{
AuthURL: "https://app.warmbly.com/oauth/authorize",
TokenURL: "https://api.warmbly.com/v1/oauth/token",
RevokeURL: "https://api.warmbly.com/v1/oauth/revoke",
}
DefaultEndpoint is the production Warmbly authorization server.
var ErrCLIAuthDenied = errors.New("warmbly: CLI sign-in was denied")
ErrCLIAuthDenied is returned by AuthService.WaitForCLIAuth when a member declined the request.
var ErrNoMorePages = errors.New("warmbly: no more pages")
ErrNoMorePages is returned by Page.Next when the current page is the last.
Functions ¶
func Bool ¶
Bool, Int, Float, String and Time return pointers to their arguments, for filling the optional fields of parameter structs inline:
params := &warmbly.EmailUpdateParams{Name: warmbly.String("Sales")}
func ComputeWebhookSignature ¶
ComputeWebhookSignature returns the expected WebhookSignatureHeader value for a payload, signing timestamp and secret: "t=<unix>,v1=<hex>", where the digest is HMAC-SHA256 over "<unix>." followed by the raw payload.
func GenerateVerifier ¶
func GenerateVerifier() string
GenerateVerifier returns a high-entropy PKCE code verifier (RFC 7636): the base64url encoding of 32 random bytes (43 characters). Generate one per authorization request, pass it to S256ChallengeOption, and supply the same value to [Exchange] via VerifierOption.
func S256ChallengeFromVerifier ¶
S256ChallengeFromVerifier derives the S256 code challenge from a verifier.
func VerifyWebhookSignature ¶
VerifyWebhookSignature reports whether signatureHeader is a valid signature for payload under secret. The digest comparison is constant-time.
It does not check the timestamp for freshness; use ConstructWebhookEvent (or VerifyWebhookSignatureAt) to also defeat replay.
Types ¶
type ABAnalysis ¶
type ABAnalysis struct {
CampaignID string `json:"campaign_id"`
Variants []ABVariantMetrics `json:"variants"`
// WinnerID and WinnerName are nil until a winner clears the sample-size
// and confidence bar.
WinnerID *string `json:"winner_id"`
WinnerName *string `json:"winner_name"`
// WinningRule is the metric the comparison was decided on.
WinningRule string `json:"winning_rule"`
// Confidence is a qualitative reading, for example "high" or "low".
Confidence string `json:"confidence"`
}
ABAnalysis compares the arms of a campaign's A/B test.
type ABTestingSettings ¶
type ABTestingSettings struct {
Enabled bool `json:"enabled"`
// DefaultWinningRule is the metric a winner is picked on, for example
// "reply_rate".
DefaultWinningRule string `json:"default_winning_rule"`
AutoPromoteWinner bool `json:"auto_promote_winner"`
MinSampleSize int `json:"min_sample_size"`
}
ABTestingSettings governs how A/B variants are compared and promoted.
type ABVariant ¶
type ABVariant struct {
ID string `json:"id"`
CampaignID string `json:"campaign_id"`
// StepID scopes the variant to a single step; nil applies it campaign-wide.
StepID *string `json:"step_id"`
Name string `json:"name"`
// Weight is the variant's share of the split.
Weight int `json:"weight"`
Subject string `json:"subject"`
BodyHTML string `json:"body_html"`
BodyPlain string `json:"body_plain"`
// IsControl marks the baseline arm the others are measured against.
IsControl bool `json:"is_control"`
IsActive bool `json:"is_active"`
Metadata map[string]any `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ABVariant is one arm of a campaign's A/B test.
type ABVariantCreateParams ¶
type ABVariantCreateParams struct {
Name string `json:"name"`
StepID string `json:"step_id,omitempty"`
Weight *int `json:"weight,omitempty"`
Subject string `json:"subject,omitempty"`
BodyHTML string `json:"body_html,omitempty"`
BodyPlain string `json:"body_plain,omitempty"`
IsControl *bool `json:"is_control,omitempty"`
IsActive *bool `json:"is_active,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
ABVariantCreateParams creates an A/B variant. Only Name is required.
type ABVariantMetrics ¶
type ABVariantMetrics struct {
VariantID string `json:"variant_id"`
VariantName string `json:"variant_name"`
TotalSent int64 `json:"total_sent"`
Opened int64 `json:"opened"`
Clicked int64 `json:"clicked"`
Replied int64 `json:"replied"`
Bounced int64 `json:"bounced"`
OpenRate float64 `json:"open_rate"`
ClickRate float64 `json:"click_rate"`
ReplyRate float64 `json:"reply_rate"`
BounceRate float64 `json:"bounce_rate"`
}
ABVariantMetrics is one variant's engagement in an ABAnalysis.
type ABVariantUpdateParams ¶
type ABVariantUpdateParams struct {
Name *string `json:"name,omitempty"`
Weight *int `json:"weight,omitempty"`
Subject *string `json:"subject,omitempty"`
BodyHTML *string `json:"body_html,omitempty"`
BodyPlain *string `json:"body_plain,omitempty"`
IsControl *bool `json:"is_control,omitempty"`
IsActive *bool `json:"is_active,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
ABVariantUpdateParams updates an A/B variant. Nil fields are unchanged.
type AIDraft ¶
type AIDraft struct {
// Text is the drafted message. It is empty when the model asked a
// clarifying Question instead.
Text string `json:"text,omitempty"`
// Question is a single clarifying question, returned when the request gave
// the model too little to work with.
Question string `json:"question,omitempty"`
// CreditsCharged is what this draft cost; CreditsRemaining is the balance
// afterwards.
CreditsCharged int `json:"credits_charged"`
CreditsRemaining int `json:"credits_remaining"`
TokensUsed int `json:"tokens_used"`
Model string `json:"model"`
// Grounding reports what context the draft was written against. It is only
// returned by [UniboxService.DraftCompose].
Grounding *AIDraftGrounding `json:"grounding,omitempty"`
}
AIDraft is a generated draft. It is never sent by the call that produced it.
type AIDraftGrounding ¶
type AIDraftGrounding struct {
// Contact is true when a contact record was found for the recipient.
Contact bool `json:"contact"`
// History is how many prior messages with the address were included. The
// model reads their stored text, not just the preview lines.
History int `json:"history"`
// VoiceProfile is true when the workspace voice profile was applied.
VoiceProfile bool `json:"voice_profile"`
}
AIDraftGrounding reports which context sources fed a compose draft.
type AISkill ¶
type AISkill struct {
ID string `json:"id"`
OrgID string `json:"org_id"`
Name string `json:"name"`
Description string `json:"description"`
// Content is the instruction text handed to the model.
Content string `json:"content"`
// Enabled reports whether the skill is currently applied.
Enabled bool `json:"enabled"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
AISkill is one workspace playbook.
type AIVariableParams ¶
type AIVariableParams struct {
// Mode is [AIVariableInstant] or [AIVariableResearch].
Mode string `json:"mode,omitempty"`
Prompt string `json:"prompt"`
Tone string `json:"tone,omitempty"`
// WebSearch lets a research-mode preview search the web.
WebSearch bool `json:"web_search,omitempty"`
// ContactID is the contact to render against.
ContactID string `json:"contact_id,omitempty"`
// ContextBefore and ContextAfter are the surrounding copy, each clamped
// server-side so a caller cannot inflate the prompt.
ContextBefore string `json:"context_before,omitempty"`
ContextAfter string `json:"context_after,omitempty"`
}
AIVariableParams previews a per-recipient AI variable block against one contact, so the editor can show what a merge tag will actually produce.
type APIKey ¶
type APIKey struct {
ID string `json:"id"`
UserID string `json:"user_id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
// KeyPrefix and KeySuffix are the non-secret ends of the key, shown so a
// human can tell two keys apart.
KeyPrefix string `json:"key_prefix"`
KeySuffix string `json:"key_suffix"`
// Permissions is the granted scope bitmask; test it with [APIKey.Can].
Permissions uint64 `json:"permissions"`
// AllowedIPs restricts use to these IPs or CIDR ranges. Empty means any.
AllowedIPs []string `json:"allowed_ips,omitempty"`
// AllowedEmailAccounts restricts the key to specific mailbox ids. Empty
// means every mailbox in the organization.
AllowedEmailAccounts []string `json:"allowed_email_accounts,omitempty"`
// RateLimitPerMinute is the per-key request ceiling, enforced as a
// sliding window. Zero means the server default (60).
RateLimitPerMinute int `json:"rate_limit_per_minute"`
// Status is [APIKeyStatusActive], [APIKeyStatusRevoked] or
// [APIKeyStatusExpired].
Status string `json:"status"`
LastUsedAt *time.Time `json:"last_used_at"`
LastRequestIP *string `json:"last_request_ip"`
ExpiresAt *time.Time `json:"expires_at"`
RevokedAt *time.Time `json:"revoked_at"`
RevokedReason *string `json:"revoked_reason"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
APIKey is an API key as returned by the API. The full secret is never included; see APIKeyWithSecret, returned only by APIKeyService.Create.
func (*APIKey) Can ¶
Can reports whether the key holds every bit in perms.
if key.Can(warmbly.PermSendCampaigns) { ... }
type APIKeyAnalytics ¶
type APIKeyAnalytics struct {
// APIKeyID is the key the report covers, or the zero UUID for the
// organization-wide report.
APIKeyID string `json:"api_key_id"`
From time.Time `json:"from"`
To time.Time `json:"to"`
// Interval is one of the Interval* constants.
Interval string `json:"interval"`
Buckets []APIKeyUsageBucket `json:"buckets"`
Endpoints []APIKeyEndpointStat `json:"endpoints"`
Total int64 `json:"total"`
Errors int64 `json:"errors"`
}
APIKeyAnalytics is call volume, latency and error rate over a window, both bucketed over time and broken down by endpoint.
type APIKeyAnalyticsParams ¶
type APIKeyAnalyticsParams struct {
// From defaults to 24 hours before To; To defaults to now. The window may
// not exceed 90 days.
From time.Time
To time.Time
// Interval is [IntervalMinute], [IntervalHour] or [IntervalDay]. Leave it
// empty to let the server pick from the window's span: minutes up to two
// hours, hours up to a week, days beyond that. The interval it settled on
// comes back in [APIKeyAnalytics.Interval].
Interval string
}
APIKeyAnalyticsParams selects the window and granularity of a usage report.
type APIKeyCreateParams ¶
type APIKeyCreateParams struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
// Permissions is the scope bitmask, for example
// [PermReadOnly] or PermReadCampaigns|PermSendCampaigns. It must name at
// least one scope, and only scopes the server knows: a mask carrying an
// unrecognized bit is refused rather than silently narrowed, so a stale
// client cannot grant a scope it does not understand.
Permissions uint64 `json:"permissions"`
// AllowedIPs restricts the key to these IPs or CIDR ranges (at most
// [MaxAllowedIPs]); AllowedEmailAccounts to these mailbox ids (at most
// [MaxAllowedEmailAccounts]). Empty means no restriction.
AllowedIPs []string `json:"allowed_ips,omitempty"`
AllowedEmailAccounts []string `json:"allowed_email_accounts,omitempty"`
// RateLimitPerMinute caps requests per minute for this key, between
// [MinRateLimitPerMinute] and [MaxRateLimitPerMinute]; zero keeps the
// server default of [DefaultRateLimitPerMinute].
RateLimitPerMinute int `json:"rate_limit_per_minute,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
}
APIKeyCreateParams provisions an API key. Name (at most 255 characters) and Permissions are required.
type APIKeyEndpointStat ¶
type APIKeyEndpointStat struct {
Endpoint string `json:"endpoint"`
Method string `json:"method"`
Count int64 `json:"count"`
ErrorCount int64 `json:"error_count"`
AvgLatencyMS float64 `json:"avg_latency_ms"`
}
APIKeyEndpointStat is one endpoint's share of the traffic.
type APIKeyService ¶
type APIKeyService service
APIKeyService manages the organization's API keys.
API keys authenticate server-to-server requests and are prefixed "wmbly_". The secret is shown exactly once, at creation; afterwards only a prefix and suffix are retrievable.
func (*APIKeyService) Analytics ¶
func (s *APIKeyService) Analytics(ctx context.Context, id string, params *APIKeyAnalyticsParams, opts ...RequestOption) (*APIKeyAnalytics, *Response, error)
Analytics returns call volume and latency for a single key.
func (*APIKeyService) Create ¶
func (s *APIKeyService) Create(ctx context.Context, params *APIKeyCreateParams, opts ...RequestOption) (*APIKeyWithSecret, *Response, error)
Create provisions a new API key. The returned APIKeyWithSecret is the only time the plaintext credential is available.
func (*APIKeyService) Get ¶
func (s *APIKeyService) Get(ctx context.Context, id string, opts ...RequestOption) (*APIKey, *Response, error)
Get retrieves a single API key by ID.
func (*APIKeyService) List ¶
func (s *APIKeyService) List(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[APIKey], error)
List returns a page of API keys.
func (*APIKeyService) Logs ¶
func (s *APIKeyService) Logs(ctx context.Context, id string, params *ListOptions, opts ...RequestOption) (*Page[APIKeyUsageLog], error)
Logs returns a page of individual requests made with a key, most recent first. The server caps ListOptions.Limit at 200 and defaults to 50.
func (*APIKeyService) Permissions ¶
func (s *APIKeyService) Permissions(ctx context.Context, opts ...RequestOption) (*PermissionCatalog, *Response, error)
Permissions lists every scope bit the API exposes, together with the preset masks.
func (*APIKeyService) Revoke ¶
func (s *APIKeyService) Revoke(ctx context.Context, id, reason string, opts ...RequestOption) (*Response, error)
Revoke permanently revokes an API key. The reason is stored on the key and may be empty.
func (*APIKeyService) RevokeSelf ¶ added in v0.3.0
func (s *APIKeyService) RevokeSelf(ctx context.Context, reason string, opts ...RequestOption) (*Response, error)
RevokeSelf revokes the key this client is authenticated with. It is the one key route that needs no scope: a credential must always be able to end itself, which is what a CLI logout promises. The reason is stored on the key and may be empty (the server records that the key revoked itself). A session caller gets a 400 — there is no key in that request to end; use AuthService.Logout. Every request after this one fails with 401.
func (*APIKeyService) Update ¶
func (s *APIKeyService) Update(ctx context.Context, id string, params *APIKeyUpdateParams, opts ...RequestOption) (*APIKey, *Response, error)
Update modifies an existing API key.
func (*APIKeyService) UsageAnalytics ¶
func (s *APIKeyService) UsageAnalytics(ctx context.Context, params *APIKeyAnalyticsParams, opts ...RequestOption) (*APIKeyAnalytics, *Response, error)
UsageAnalytics returns call volume and latency across every key in the organization.
func (*APIKeyService) UsageSummary ¶
func (s *APIKeyService) UsageSummary(ctx context.Context, opts ...RequestOption) (*APIKeyUsageSummary, *Response, error)
UsageSummary returns a rollup of the organization's key usage.
type APIKeyUpdateParams ¶
type APIKeyUpdateParams struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Permissions *uint64 `json:"permissions,omitempty"`
AllowedIPs *[]string `json:"allowed_ips,omitempty"`
AllowedEmailAccounts *[]string `json:"allowed_email_accounts,omitempty"`
RateLimitPerMinute *int `json:"rate_limit_per_minute,omitempty"`
}
APIKeyUpdateParams updates an API key. Nil fields are left unchanged; an empty (non-nil) AllowedIPs or AllowedEmailAccounts clears the restriction. Permissions is validated the same way as on create: non-zero, and only scopes the server knows.
type APIKeyUsageBucket ¶
type APIKeyUsageBucket struct {
Bucket time.Time `json:"bucket"`
Total int64 `json:"total"`
Success int64 `json:"success"`
ClientErrors int64 `json:"client_errors"`
ServerErrors int64 `json:"server_errors"`
AvgLatencyMS float64 `json:"avg_latency_ms"`
}
APIKeyUsageBucket is one time bucket of API traffic.
type APIKeyUsageLog ¶
type APIKeyUsageLog struct {
ID string `json:"id"`
APIKeyID string `json:"api_key_id"`
Endpoint string `json:"endpoint"`
Method string `json:"method"`
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
ResponseCode int `json:"response_code"`
ResponseTimeMS int `json:"response_time_ms"`
CreatedAt time.Time `json:"created_at"`
}
APIKeyUsageLog is a single recorded API request made with a key.
type APIKeyUsageSummary ¶
type APIKeyUsageSummary struct {
ActiveKeys int `json:"active_keys"`
RevokedKeys int `json:"revoked_keys"`
ExpiredKeys int `json:"expired_keys"`
// Requests24h and Errors24h cover the last rolling day.
Requests24h int64 `json:"requests_24h"`
Errors24h int64 `json:"errors_24h"`
AvgLatencyMS24h float64 `json:"avg_latency_ms_24h"`
LastCallAt *time.Time `json:"last_call_at"`
}
APIKeyUsageSummary is a rollup of the organization's key usage.
type APIKeyWithSecret ¶
type APIKeyWithSecret struct {
APIKey
// Secret is the full plaintext credential (prefixed "wmbly_"). Capture it
// now; it cannot be retrieved again.
Secret string `json:"secret"`
}
APIKeyWithSecret is an API key together with its plaintext secret, returned only by APIKeyService.Create.
type APIUsage ¶
type APIUsage struct {
TotalCalls int64 `json:"total_calls"`
DailyLimit int64 `json:"daily_limit"`
// TopEndpoints are the busiest endpoints, each carrying its own endpoint
// and count keys.
TopEndpoints []map[string]any `json:"top_endpoints,omitempty"`
}
APIUsage is API call volume against the plan's daily limit.
type AccountDailyUsage ¶
type AccountDailyUsage struct {
Date string `json:"date"`
CampaignSent int64 `json:"campaign_sent"`
CampaignLimit int64 `json:"campaign_limit"`
WarmupSent int64 `json:"warmup_sent"`
WarmupLimit int64 `json:"warmup_limit"`
}
AccountDailyUsage is a mailbox's sending against today's caps. The warmup pair is omitted (zero) for a mailbox that is not warming.
type AccountError ¶
type AccountError struct {
ID string `json:"id"`
ErrorCode string `json:"error_code"`
Severity string `json:"severity"`
Title string `json:"title"`
Message string `json:"message"`
// ActionRequired tells the mailbox owner what to do about it, when there
// is something to do.
ActionRequired *string `json:"action_required,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
AccountError is a recent error recorded against a mailbox.
type AccountHealth ¶
type AccountHealth struct {
Status string `json:"status"`
// Score runs 0 to 100, higher being healthier.
Score int `json:"score"`
Issues []string `json:"issues,omitempty"`
}
AccountHealth is a mailbox's health verdict.
type AccountHealthTotals ¶
type AccountHealthTotals struct {
TotalAccounts int `json:"total_accounts"`
HealthyAccounts int `json:"healthy_accounts"`
WarningAccounts int `json:"warning_accounts"`
ErrorAccounts int `json:"error_accounts"`
}
AccountHealthTotals counts mailboxes by health band.
type AccountStatus ¶
type AccountStatus struct {
ID string `json:"id"`
Email string `json:"email"`
Provider string `json:"provider"`
Status string `json:"status"`
LastSyncedAt *time.Time `json:"last_synced_at"`
Health AccountHealth `json:"health"`
Errors []AccountError `json:"errors,omitempty"`
DailyUsage AccountDailyUsage `json:"daily_usage"`
// WarmupStatus is the warmup ramp, present once warmup has ever been
// enabled (running or paused).
WarmupStatus *WarmupStatus `json:"warmup_status,omitempty"`
// WarmupHealth is the mailbox's standing in the warmup pool. It is folded
// into Health.Score and nil when the mailbox is not in a pool.
WarmupHealth *WarmupHealth `json:"warmup_health,omitempty"`
// InCampaign reports whether the mailbox is attached to a running campaign.
// When true a low-volume health-check warmup keeps running even if warmup
// is paused or off.
InCampaign bool `json:"in_campaign"`
// SendLifecycle is present only when the mailbox is NOT in cold rotation
// (resting or held in reserve); an active mailbox needs no explanation.
SendLifecycle *SendLifecycleState `json:"send_lifecycle,omitempty"`
// ColdRamp is present only while the warmup-to-cold graduation ceiling
// holds today's cold allowance below the mailbox's own campaign limit.
ColdRamp *ColdRamp `json:"cold_ramp,omitempty"`
}
AccountStatus is one mailbox's operational state: health, recent errors, how much of its daily allowance it has used, and anything currently holding its volume down.
type ActivityEvent ¶
type ActivityEvent struct {
// Type is the engagement, for example "open", "click" or "reply".
Type string `json:"type"`
CampaignID string `json:"campaign_id"`
CampaignName string `json:"campaign_name"`
ContactEmail string `json:"contact_email"`
ContactID string `json:"contact_id"`
Timestamp time.Time `json:"timestamp"`
// Link is the URL that was clicked, on click events.
Link string `json:"link,omitempty"`
}
ActivityEvent is one recent engagement event on the dashboard feed.
type AddToCampaignConfig ¶ added in v0.3.0
type AddToCampaignConfig struct {
CampaignID string `json:"campaign_id"`
}
AddToCampaignConfig is the config of an ActionAddToCampaign node. CampaignID is required and validated on save.
func (*AddToCampaignConfig) Config ¶ added in v0.3.0
func (c *AddToCampaignConfig) Config() (json.RawMessage, error)
Config renders the struct as an AutomationNode.Config value.
type AdvisorAction ¶
type AdvisorAction struct {
// Tool is the registry name of what would run, and Args its payload.
Tool string `json:"tool"`
Args json.RawMessage `json:"args"`
// Label is the button text.
Label string `json:"label"`
// Auto marks a fix autopilot may apply unattended. It is true only for a
// bounded, reversible settings change in the safe direction.
Auto bool `json:"auto,omitempty"`
// Preview is the exact before and after.
Preview []AdvisorPreviewChange `json:"preview,omitempty"`
// Undo, when set, reverts the action.
Undo *AdvisorUndo `json:"undo,omitempty"`
}
AdvisorAction is a finding's one-click remedy. It runs as the calling member with their permissions enforced.
type AdvisorAgentResult ¶
type AdvisorAgentResult struct {
FindingID string `json:"finding_id"`
// Applied is true only when the agent actually changed something. A run
// that looked and decided nothing was wrong reports false and the finding
// stays open.
Applied bool `json:"applied"`
// Summary is the agent's own account of what it did.
Summary string `json:"summary"`
// Steps are the calls it made, in order, so they can be checked against
// the audit log.
Steps []string `json:"steps,omitempty"`
}
AdvisorAgentResult is what an agent fix reports back.
type AdvisorFinding ¶
type AdvisorFinding struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
// DetectorKey identifies the check that produced the finding.
DetectorKey string `json:"detector_key"`
// Category is one of the AdvisorCategory* constants, Severity one of the
// Advisor{Critical,High,Medium,Low} constants, and Surface one of the
// AdvisorSurface* constants.
Category string `json:"category"`
Severity string `json:"severity"`
Surface string `json:"surface"`
// EntityType, EntityID and EntityLabel name what the finding is about.
EntityType string `json:"entity_type,omitempty"`
EntityID *string `json:"entity_id,omitempty"`
EntityLabel string `json:"entity_label,omitempty"`
// ParentType and ParentID name where the finding belongs when that differs
// from its subject: a step's copy problem belongs to its campaign.
ParentType string `json:"parent_type,omitempty"`
ParentID *string `json:"parent_id,omitempty"`
// Status is one of the AdvisorStatus* constants.
Status string `json:"status"`
// Impact ranks the finding against the others.
Impact int `json:"impact"`
Title string `json:"title"`
// GroupTitle names the finding when several of its kind are listed
// together, with a {count} placeholder. Empty means it always stands alone.
GroupTitle string `json:"group_title,omitempty"`
Detail string `json:"detail"`
Remedy string `json:"remedy"`
// Steps is the manual how-to, set only on findings with no one-click fix.
Steps []string `json:"steps,omitempty"`
// AgentFixable reports whether [AdvisorService.AgentFix] could resolve
// this. It is false for anything outside the platform, such as a DNS
// record, so a client shows the steps rather than a button that cannot
// succeed.
AgentFixable bool `json:"agent_fixable"`
// Snippets are exact values to paste somewhere the platform cannot reach.
Snippets []AdvisorSnippet `json:"snippets,omitempty"`
// Narrated is false while the finding still shows built-in fallback copy
// rather than AI narration. It is fully usable either way.
Narrated bool `json:"narrated"`
// Evidence is the detector's raw supporting data.
Evidence json.RawMessage `json:"evidence,omitempty"`
// Action is the one-click remedy, when there is one.
Action *AdvisorAction `json:"action,omitempty"`
FirstSeenAt time.Time `json:"first_seen_at"`
LastSeenAt time.Time `json:"last_seen_at"`
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
SnoozedUntil *time.Time `json:"snoozed_until,omitempty"`
DismissedAt *time.Time `json:"dismissed_at,omitempty"`
DismissReason string `json:"dismiss_reason,omitempty"`
AppliedAt *time.Time `json:"applied_at,omitempty"`
AppliedBy *string `json:"applied_by,omitempty"`
AppliedResult string `json:"applied_result,omitempty"`
}
AdvisorFinding is one piece of advice about one entity.
type AdvisorListParams ¶
type AdvisorListParams struct {
// Surface is one of the AdvisorSurface* constants.
Surface string
// Category is one of the AdvisorCategory* constants.
Category string
// EntityType and EntityID narrow to one entity.
EntityType string
EntityID string
// Statuses matches any of the AdvisorStatus* constants. The default is
// open findings.
Statuses []string
// Limit caps the rows returned, from 1 to 200.
Limit int
}
AdvisorListParams filters the findings list.
type AdvisorPreviewChange ¶
type AdvisorPreviewChange struct {
Field string `json:"field"`
From string `json:"from"`
To string `json:"to"`
}
AdvisorPreviewChange is one field an action would change.
type AdvisorService ¶
type AdvisorService service
AdvisorService reads and acts on the Advisor: continuous checks on the workspace's sending posture, surfaced as findings on the thing they are about.
A finding either carries a one-click AdvisorAction, can be handed to an agent with AdvisorService.AgentFix, or comes with AdvisorFinding.Steps and AdvisorFinding.Snippets for what the platform cannot reach itself, such as a DNS record.
Applying a fix runs through the same permission checks as doing it by hand, so a viewer sees the advice and gets a clean 403 if they try to apply it.
func (*AdvisorService) AgentFix ¶
func (s *AdvisorService) AgentFix(ctx context.Context, id string, opts ...RequestOption) (*AdvisorAgentResult, *Response, error)
AgentFix hands a finding to a bounded agent for the cases a settings change cannot resolve. It spends AI credits, acts as the calling member inside their permissions, and reports the calls it actually made.
This route is session-only: it is not reachable with an API key.
func (*AdvisorService) Apply ¶
func (s *AdvisorService) Apply(ctx context.Context, id string, opts ...RequestOption) (*AdvisorFinding, *Response, error)
Apply performs a finding's one-click remedy and returns the updated finding. It runs as the calling member, so it fails with a 403 if they could not make the same change by hand.
func (*AdvisorService) Dismiss ¶
func (s *AdvisorService) Dismiss(ctx context.Context, id, reason string, opts ...RequestOption) (*Response, error)
Dismiss rejects a finding. The dismissal sticks until the underlying condition clears and later recurs.
func (*AdvisorService) Feedback ¶
func (s *AdvisorService) Feedback(ctx context.Context, id string, helpful bool, reason string, opts ...RequestOption) (*Response, error)
Feedback records whether a finding was helpful, which feeds detector tuning.
func (*AdvisorService) Recommendations ¶
func (s *AdvisorService) Recommendations(ctx context.Context, params *AdvisorListParams, opts ...RequestOption) ([]AdvisorFinding, *Response, error)
Recommendations returns the workspace's findings.
func (*AdvisorService) Refresh ¶
func (s *AdvisorService) Refresh(ctx context.Context, opts ...RequestOption) (*AdvisorSummary, *Response, error)
Refresh triggers a re-evaluation and returns the summary. The re-run happens in the background, so the summary may still reflect the previous pass.
func (*AdvisorService) Settings ¶
func (s *AdvisorService) Settings(ctx context.Context, opts ...RequestOption) (*AdvisorSettings, *Response, error)
Settings returns which Advisor checks are enabled for the workspace.
func (*AdvisorService) Snooze ¶
func (s *AdvisorService) Snooze(ctx context.Context, id string, days int, opts ...RequestOption) (*Response, error)
Snooze hides a finding for a bounded number of days, from 1 to 90. An unbounded snooze would be a dismissal in disguise, so use AdvisorService.Dismiss for that.
func (*AdvisorService) Summary ¶
func (s *AdvisorService) Summary(ctx context.Context, opts ...RequestOption) (*AdvisorSummary, *Response, error)
Summary returns the workspace health score and the per-surface badge counts.
func (*AdvisorService) Undo ¶
func (s *AdvisorService) Undo(ctx context.Context, id string, opts ...RequestOption) (*AdvisorFinding, *Response, error)
Undo reverts an applied remedy.
func (*AdvisorService) UpdateSettings ¶
func (s *AdvisorService) UpdateSettings(ctx context.Context, settings *AdvisorSettings, opts ...RequestOption) (*AdvisorSettings, *Response, error)
UpdateSettings replaces the Advisor configuration. Silencing checks for a whole workspace is governance, so this route is session-only and needs the manage-settings permission.
type AdvisorSettings ¶
type AdvisorSettings struct {
OrganizationID string `json:"organization_id"`
Enabled bool `json:"enabled"`
// MutedCategories holds AdvisorCategory* values, MutedDetectors holds
// detector keys.
MutedCategories []string `json:"muted_categories"`
MutedDetectors []string `json:"muted_detectors"`
// MinSeverity hides anything below it.
MinSeverity string `json:"min_severity"`
// Autopilot applies auto-safe fixes on its own. It is off by default.
Autopilot bool `json:"autopilot"`
// AutopilotActorID is the member autopilot acts as. It is set to whoever
// switched it on, and autopilot stops if they leave.
AutopilotActorID *string `json:"autopilot_actor_id,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
}
AdvisorSettings controls which checks run for the workspace. Reading it is an analytics read; changing it is workspace governance and is session-only.
type AdvisorSnippet ¶
type AdvisorSnippet struct {
// Label names the field in the target system's own words.
Label string `json:"label"`
Value string `json:"value"`
// Note is the caveat that trips people up on this specific field.
Note string `json:"note,omitempty"`
}
AdvisorSnippet is an exact value to paste into something outside Warmbly, such as a DNS record.
type AdvisorSummary ¶
type AdvisorSummary struct {
// Score is 0-100, falling as open findings accumulate and weighted so one
// critical finding outweighs a pile of low-severity nits.
Score int `json:"score"`
Total int `json:"total"`
Critical int `json:"critical"`
High int `json:"high"`
Medium int `json:"medium"`
Low int `json:"low"`
Surfaces []AdvisorSurfaceCount `json:"surfaces"`
// LastRunAt is nil before the first evaluation.
LastRunAt *time.Time `json:"last_run_at,omitempty"`
}
AdvisorSummary is the workspace rollup behind the health score and the per-tab badges.
type AdvisorSurfaceCount ¶
type AdvisorSurfaceCount struct {
// Surface is one of the AdvisorSurface* constants.
Surface string `json:"surface"`
// Total is every open finding on the surface; Critical and High set the
// badge's tone.
Total int `json:"total"`
Critical int `json:"critical"`
High int `json:"high"`
}
AdvisorSurfaceCount is one surface's badge payload.
type AdvisorUndo ¶
type AdvisorUndo struct {
Tool string `json:"tool"`
Args json.RawMessage `json:"args"`
}
AdvisorUndo reverts an applied action.
type AgentBlock ¶
type AgentBlock struct {
// Kind is "text" or "tool".
Kind string `json:"kind"`
Text string `json:"text,omitempty"`
Tool string `json:"tool,omitempty"`
ArgsSummary string `json:"args_summary,omitempty"`
Result string `json:"result,omitempty"`
// EntityType, EntityID and OpenURL point at something the tool created, so
// a client can link straight to it.
EntityType string `json:"entity_type,omitempty"`
EntityID string `json:"entity_id,omitempty"`
OpenURL string `json:"open_url,omitempty"`
// Done is false while a tool step is still running.
Done bool `json:"done"`
}
AgentBlock is one piece of a turn.
type AgentDraft ¶
type AgentDraft struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
EmailAccountID string `json:"email_account_id"`
// OwnerUserID is the mailbox owner; an approved send goes out as them.
OwnerUserID string `json:"owner_user_id"`
ThreadID string `json:"thread_id"`
// SourceMessageID is the inbound message being replied to.
SourceMessageID *string `json:"source_message_id,omitempty"`
ContactID *string `json:"contact_id,omitempty"`
CampaignID *string `json:"campaign_id,omitempty"`
ToAddr string `json:"to_addr"`
Subject string `json:"subject"`
// InReplyTo is the Message-ID referenced on send.
InReplyTo string `json:"in_reply_to"`
Body string `json:"body"`
// IntentClass is how the agent read the inbound reply, and Confidence how
// sure it was.
IntentClass string `json:"intent_class"`
Confidence float64 `json:"confidence"`
Model string `json:"model"`
// Status is one of the AgentDraft* constants.
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
AgentDraft is a reply the inbox agent suggested for an inbound human reply. It is never sent until someone approves it.
type AgentEvent ¶
type AgentEvent struct {
// Type is one of the AgentEvent* constants.
Type string `json:"type"`
// Text is reply content, whole or incremental.
Text string `json:"text,omitempty"`
// Tool, Risk, ArgsSummary and ToolCallID describe a tool step.
Tool string `json:"tool,omitempty"`
Risk string `json:"risk,omitempty"`
ArgsSummary string `json:"args_summary,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
Result string `json:"result,omitempty"`
// Iteration counts the assistant's turns within the run, and Budget caps
// them.
Iteration int `json:"iteration,omitempty"`
Budget int `json:"budget,omitempty"`
// CreditsRemaining is the balance after this step; FreeModel means nothing
// was charged.
CreditsRemaining int `json:"credits_remaining,omitempty"`
FreeModel bool `json:"free_model,omitempty"`
// Code and Message are set on [AgentEventError].
Code string `json:"code,omitempty"`
Message string `json:"message,omitempty"`
// EntityType, EntityID and OpenURL point at something a tool created.
EntityType string `json:"entity_type,omitempty"`
EntityID string `json:"entity_id,omitempty"`
OpenURL string `json:"open_url,omitempty"`
}
AgentEvent is one step of a streamed run. Which fields are set depends on Type.
type AgentSession ¶
type AgentSession struct {
ID string `json:"id"`
OrgID string `json:"org_id"`
UserID string `json:"user_id"`
Title string `json:"title"`
// UserName attributes the conversation in a workspace-shared history; see
// [Organization.AssistantSharedHistory].
UserName string `json:"user_name,omitempty"`
Context AgentSessionContext `json:"context"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
AgentSession is one assistant conversation.
type AgentSessionContext ¶
type AgentSessionContext struct {
// Page and Resource are what the caller was looking at, folded into the
// prompt so "this campaign" resolves.
Page string `json:"page,omitempty"`
Resource string `json:"resource,omitempty"`
// Model is the provider model resolved for this session.
Model string `json:"model,omitempty"`
// FreeModel reports that the run used a free or local backend, in which
// case no credits were charged.
FreeModel bool `json:"free_model,omitempty"`
// Pending is the tool call awaiting approval when a run is paused.
Pending *PendingTool `json:"pending,omitempty"`
}
AgentSessionContext is what the assistant knows about the session beyond its messages.
type AgentTool ¶ added in v0.3.0
type AgentTool struct {
// Name is the identifier to pass to [AgentToolService.Call].
Name string `json:"name"`
// Description is the model-facing explanation of what the tool does and
// when to use it.
Description string `json:"description"`
// InputSchema is the JSON Schema of the argument object, kept verbatim so
// it drops into a function-calling client unchanged. It is always an
// object schema; a tool with no arguments has an empty properties map.
InputSchema json.RawMessage `json:"input_schema"`
}
AgentTool is one registry tool the caller is permitted to use, as returned by AgentToolService.List.
The server does not report a tool's risk class or the scope it checks; the list is already filtered to what the credential allows, so everything in it is callable with the same credential.
func (AgentTool) Function ¶ added in v0.3.0
func (t AgentTool) Function() AgentToolFunction
Function converts the tool to the OpenAI function-calling shape, without a round trip to the server. It is what AgentToolService.ListFunctions returns, built locally.
type AgentToolCallResult ¶ added in v0.3.0
type AgentToolCallResult struct {
// Name echoes the tool that ran.
Name string `json:"name"`
// Result is the tool's output. It is the tool's JSON embedded directly
// when the tool produced JSON (every registry tool does today) and a JSON
// string otherwise, so it is always valid JSON and can be fed back to the
// model as the tool-call result unchanged.
Result json.RawMessage `json:"result"`
}
AgentToolCallResult is what one tool call returned.
func (*AgentToolCallResult) Decode ¶ added in v0.3.0
func (r *AgentToolCallResult) Decode(v any) error
Decode unmarshals the tool's output into v, for callers that know the shape a particular tool produces.
type AgentToolFunction ¶ added in v0.3.0
type AgentToolFunction struct {
// Type is always "function".
Type string `json:"type"`
Function AgentToolFunctionSpec `json:"function"`
}
AgentToolFunction is a tool in OpenAI function-calling form: {"type":"function","function":{...}}. The objects go verbatim into an OpenAI-compatible tools array or a Hermes <tools> block.
func AgentToolFunctions ¶ added in v0.3.0
func AgentToolFunctions(tools []AgentTool) []AgentToolFunction
AgentToolFunctions converts a tool list to OpenAI function-calling objects, for a client that fetched the default shape and also wants the manifest.
type AgentToolFunctionSpec ¶ added in v0.3.0
type AgentToolFunctionSpec struct {
Name string `json:"name"`
Description string `json:"description"`
// Parameters is the argument JSON Schema, the same bytes as
// [AgentTool.InputSchema].
Parameters json.RawMessage `json:"parameters"`
}
AgentToolFunctionSpec is the function half of an AgentToolFunction.
type AgentToolService ¶ added in v0.3.0
type AgentToolService service
AgentToolService is the AI tool registry over plain HTTP, for function-calling agents that do not speak MCP: Hermes-style models, OpenAI-compatible frameworks, LangChain executors, plain scripts. It is the same registry that POST /v1/mcp exposes, gated the same way, so a tool behaves identically whichever door it came through.
There is no route-level scope on these endpoints. Each tool enforces its own permission — the API-key scope for key and OAuth callers, the organization permission for session callers — and AgentToolService.List only ever shows what the caller may use, so the whole list can be handed to a model as-is. Send-class tools (anything that puts real mail on the wire) are never listed and never callable here: an agent wired through this surface can read, search, label and draft, but a human presses send.
A call runs as the caller with their permissions, exactly as the matching REST route would; a tool can never do more than the credential could through the normal API. Write-class tools audit like the routes they wrap.
func (*AgentToolService) Call ¶ added in v0.3.0
func (s *AgentToolService) Call(ctx context.Context, name string, args any, opts ...RequestOption) (*AgentToolCallResult, *Response, error)
Call runs one tool by name. args is the tool's argument object exactly as the model produced it — a map, a struct, or the raw json.RawMessage from the model's tool call — and must encode to a JSON object matching the tool's AgentTool.InputSchema. A nil args sends no body, which the server treats as no arguments.
Failures map onto the package sentinels:
- ErrNotFound (404, code "not_found"): no such tool. A send-class tool answers the same way on purpose, so a name a model saw elsewhere (for example the dashboard assistant's send_reply) is indistinguishable from a typo here.
- ErrForbidden (403, code "forbidden"): the credential lacks the tool's permission. It would not have appeared in AgentToolService.List.
- ErrBadRequest (400, code "bad_request"): the body was not valid JSON.
- ErrUnprocessable (422, code "unprocessable"): the tool itself failed — arguments that decoded but did not validate, a missing record, an entitlement the workspace lacks. The Error.Message is written for the model to read and react to; feed it back as the tool result rather than treating it as a transport error.
Calls run under the write rate limit and honor WithIdempotencyKey like every other mutating request, so a retried call with the same key replays the stored result instead of running the tool again.
func (*AgentToolService) List ¶ added in v0.3.0
func (s *AgentToolService) List(ctx context.Context, opts ...RequestOption) ([]AgentTool, *Response, error)
List returns the tools the caller's credential may use, in registry order, in the default {name, description, input_schema} shape. Use AgentTool.Function or AgentToolFunctions to convert locally, or AgentToolService.ListFunctions to have the server do it.
Fetch it once at session start: the set only changes when the credential's scopes do. The read rate limit applies.
func (*AgentToolService) ListFunctions ¶ added in v0.3.0
func (s *AgentToolService) ListFunctions(ctx context.Context, opts ...RequestOption) ([]AgentToolFunction, *Response, error)
ListFunctions is AgentToolService.List with the server rendering OpenAI function-calling objects (GET /ai/tools?format=openai), ready for an OpenAI-compatible tools array or a Hermes <tools> block. The filtering is identical; only the shape differs.
type AgentTranscript ¶
type AgentTranscript struct {
Title string `json:"title"`
Turns []AgentTurn `json:"turns"`
// Pending is set when the conversation is waiting on an approval.
Pending *PendingTool `json:"pending,omitempty"`
// FreeModel reports that the session ran without charging credits.
FreeModel bool `json:"free_model"`
}
AgentTranscript is a session rehydrated for display.
type AgentTurn ¶
type AgentTurn struct {
// Role is "user" or "assistant".
Role string `json:"role"`
Blocks []AgentBlock `json:"blocks"`
}
AgentTurn is one user or assistant turn. An assistant turn interleaves text and tool steps in the order they happened.
type AnalyticsService ¶
type AnalyticsService service
AnalyticsService reads aggregate analytics: the organization dashboard, per-campaign engagement, warmup progress, deliverability health, mailbox status and plan usage. Every operation is read-only.
The date-range endpoints take plain calendar days, which the SDK formats as YYYY-MM-DD in UTC.
func (*AnalyticsService) Account ¶
func (s *AnalyticsService) Account(ctx context.Context, id string, opts ...RequestOption) (*AccountStatus, *Response, error)
Account returns one mailbox's operational status, including its warmup ramp, any cold-ramp ceiling and any lifecycle hold.
func (*AnalyticsService) Accounts ¶
func (s *AnalyticsService) Accounts(ctx context.Context, opts ...RequestOption) ([]AccountStatus, *Response, error)
Accounts returns the operational status of every mailbox.
func (*AnalyticsService) Campaign ¶
func (s *AnalyticsService) Campaign(ctx context.Context, id string, opts ...RequestOption) (*CampaignAnalytics, *Response, error)
Campaign returns one campaign's engagement, broken down by step.
func (*AnalyticsService) CampaignDaily ¶
func (s *AnalyticsService) CampaignDaily(ctx context.Context, id string, from, to time.Time, opts ...RequestOption) ([]DailyStat, *Response, error)
CampaignDaily returns a campaign's day-by-day engagement over a date range.
func (*AnalyticsService) CampaignHourly ¶
func (s *AnalyticsService) CampaignHourly(ctx context.Context, id string, date time.Time, opts ...RequestOption) ([]HourlyStat, *Response, error)
CampaignHourly returns a campaign's hour-by-hour engagement for one day. A zero date reports today.
func (*AnalyticsService) CompareCampaigns ¶
func (s *AnalyticsService) CompareCampaigns(ctx context.Context, ids []string, from, to time.Time, opts ...RequestOption) (*CampaignComparison, *Response, error)
CompareCampaigns compares up to ten campaigns over one date range.
func (*AnalyticsService) Dashboard ¶
func (s *AnalyticsService) Dashboard(ctx context.Context, period string, opts ...RequestOption) (*DashboardAnalytics, *Response, error)
Dashboard returns the organization-wide engagement summary. Period is Period7Days, Period30Days or Period90Days; anything else falls back to Period7Days.
func (*AnalyticsService) Deliverability ¶
func (s *AnalyticsService) Deliverability(ctx context.Context, from, to time.Time, opts ...RequestOption) (*DeliverabilityDashboard, *Response, error)
Deliverability returns the organization's sending health over a window. Zero times default to the last seven days.
func (*AnalyticsService) Usage ¶
func (s *AnalyticsService) Usage(ctx context.Context, period string, opts ...RequestOption) (*UsageOverview, *Response, error)
Usage returns the organization's consumption against its plan. Period is UsagePeriodDay, UsagePeriodWeek or UsagePeriodMonth.
func (*AnalyticsService) Warmup ¶
func (s *AnalyticsService) Warmup(ctx context.Context, emailID string, from, to time.Time, opts ...RequestOption) (*WarmupAnalytics, *Response, error)
Warmup returns warmup progress over a date range. Pass an empty emailID for the whole organization.
type AssistantService ¶
type AssistantService service
AssistantService drives the workspace AI assistant: conversations, their transcripts, and the streamed runs that answer a message.
The assistant acts as the calling member. Every tool it runs is re-checked against that member's permissions, and anything that sends mail or spends money pauses for an explicit approval. Runs spend AI credits.
These routes are session-only — no API key can drive the assistant — and need the use-AI permission.
func (*AssistantService) Approve ¶
func (s *AssistantService) Approve(ctx context.Context, sessionID, decision string, fn func(*AgentEvent) bool, opts ...RequestOption) (*Response, error)
Approve answers a paused approval and streams the rest of the run. The decision is ApprovalApprove, ApprovalDeny or ApprovalAlwaysAllow.
func (*AssistantService) ClearSessions ¶
func (s *AssistantService) ClearSessions(ctx context.Context, opts ...RequestOption) (*Response, error)
ClearSessions removes every conversation the caller can see.
func (*AssistantService) ConnectMCPServer ¶
func (s *AssistantService) ConnectMCPServer(ctx context.Context, params *MCPServerParams, opts ...RequestOption) (*MCPServer, *Response, error)
ConnectMCPServer registers an external MCP server and discovers its tools.
func (*AssistantService) CreateSession ¶
func (s *AssistantService) CreateSession(ctx context.Context, page, resource string, opts ...RequestOption) (*AgentSession, *Response, error)
CreateSession opens a new conversation, optionally anchored to what the user is looking at.
func (*AssistantService) DeleteMCPServer ¶
func (s *AssistantService) DeleteMCPServer(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeleteMCPServer disconnects a server and forgets its credential.
func (*AssistantService) DeleteSession ¶
func (s *AssistantService) DeleteSession(ctx context.Context, sessionID string, opts ...RequestOption) (*Response, error)
DeleteSession removes one conversation.
func (*AssistantService) MCPServers ¶
func (s *AssistantService) MCPServers(ctx context.Context, opts ...RequestOption) ([]MCPServer, *Response, error)
MCPServers returns the workspace's connected MCP servers.
func (*AssistantService) RefreshMCPServer ¶
func (s *AssistantService) RefreshMCPServer(ctx context.Context, id string, opts ...RequestOption) (*MCPServer, *Response, error)
RefreshMCPServer re-discovers a connected server's tools.
func (*AssistantService) SendMessage ¶
func (s *AssistantService) SendMessage(ctx context.Context, sessionID string, params *MessageParams, fn func(*AgentEvent) bool, opts ...RequestOption) (*Response, error)
SendMessage runs the assistant on a message and streams the run, calling fn for each step as it arrives. Return false from fn to stop reading early.
The run pauses at AgentEventApprovalRequired and ends there; answer it with AssistantService.Approve, which streams the remainder.
_, err := client.Assistant.SendMessage(ctx, sessionID,
&warmbly.MessageParams{Text: "Which campaigns are bouncing?"},
func(ev *warmbly.AgentEvent) bool {
if ev.Type == warmbly.AgentEventTextDelta {
fmt.Print(ev.Text)
}
return true
})
func (*AssistantService) Sessions ¶
func (s *AssistantService) Sessions(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[AgentSession], error)
Sessions returns a page of the caller's conversations, newest first. With Organization.AssistantSharedHistory on, it returns the whole workspace's.
func (*AssistantService) Transcript ¶
func (s *AssistantService) Transcript(ctx context.Context, sessionID string, opts ...RequestOption) (*AgentTranscript, *Response, error)
Transcript returns a conversation rehydrated for display, including any pending approval.
func (*AssistantService) UpdateMCPServer ¶
func (s *AssistantService) UpdateMCPServer(ctx context.Context, id string, params *MCPServerUpdateParams, opts ...RequestOption) (*MCPServer, *Response, error)
UpdateMCPServer changes a connected server's name, credential or enabled state.
type AuditActor ¶
type AuditActor struct {
ID string `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
}
AuditActor is the member who performed an audited action.
type AuditLog ¶
type AuditLog struct {
ID string `json:"id"`
OrgID string `json:"org_id"`
// UserID is the acting member's id; Actor carries their hydrated profile
// when the record could be joined.
UserID string `json:"user_id"`
Actor *AuditActor `json:"actor,omitempty"`
ActionDate time.Time `json:"action_date"`
// Action is what happened, for example [AuditActionUpdate].
Action string `json:"action"`
// EntityType is what it happened to, for example [AuditEntityCampaign].
EntityType string `json:"entity_type"`
EntityID *string `json:"entity_id,omitempty"`
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
// Changes records the fields that moved; Metadata carries extra context.
Changes map[string]string `json:"changes,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
AuditLog is one entry in the organization's audit trail.
type AuditLogListParams ¶
type AuditLogListParams struct {
ListOptions
// ActorID limits the trail to one acting member.
ActorID string
// EntityID limits it to one entity, and EntityType to one kind of entity.
EntityID string
EntityType string
// Action limits it to one action.
Action string
// Date selects a single UTC day. StartDate and EndDate override it with an
// explicit range.
Date time.Time
StartDate time.Time
EndDate time.Time
}
AuditLogListParams filters and paginates the audit trail.
type AuditLogService ¶
type AuditLogService service
AuditLogService reads the organization's audit trail: who changed what, when and from where. The trail is org-scoped server-side, so one organization can never read another's.
func (*AuditLogService) List ¶
func (s *AuditLogService) List(ctx context.Context, params *AuditLogListParams, opts ...RequestOption) (*Page[AuditLog], error)
List returns a page of audit-trail entries, newest first. The page size must be between 10 and 200; zero uses the server default of 50.
type AuthCodeOption ¶
type AuthCodeOption interface {
// contains filtered or unexported methods
}
AuthCodeOption customizes the parameters of an authorization or token request.
func S256ChallengeOption ¶
func S256ChallengeOption(verifier string) AuthCodeOption
S256ChallengeOption adds an S256 PKCE challenge derived from verifier to an OAuth2Config.AuthCodeURL call.
func SetAuthURLParam ¶
func SetAuthURLParam(key, value string) AuthCodeOption
SetAuthURLParam sets an arbitrary key/value parameter on the request.
func VerifierOption ¶
func VerifierOption(verifier string) AuthCodeOption
VerifierOption supplies the PKCE code verifier to an OAuth2Config.Exchange call.
type AuthConfig ¶ added in v0.3.0
type AuthConfig struct {
// Captcha reports whether a Turnstile token is verified. When false do not
// collect one: an air-gapped install cannot reach the challenge service.
Captcha bool `json:"captcha"`
// PasswordLogin is false when the deployment authenticates only through
// SSO or passkeys; [AuthService.Login] and [AuthService.Register] are then
// refused.
PasswordLogin bool `json:"password_login"`
// LoginCode is [LoginCodeAlways], [LoginCodeNewDevice] or [LoginCodeOff].
LoginCode string `json:"login_code"`
// Registration is [RegistrationOpen], [RegistrationInviteOnly] or
// [RegistrationClosed], already resolved through the first-launch
// exemption (a brand new instance reports open signups).
Registration string `json:"registration"`
// EmailVerification reports whether a signup must confirm an emailed code.
EmailVerification bool `json:"email_verification"`
// MailDelivers is false when the platform's mail transport writes to a log
// instead of the wire, so emailed codes never arrive and the operator has
// to read them from the server.
MailDelivers bool `json:"mail_delivers"`
// Passkeys reports whether WebAuthn can work here: it needs a secure
// context, so a plain-http origin disables it.
Passkeys bool `json:"passkeys"`
// Providers are the browser SSO providers this backend can complete a
// sign-in with (the SSOProvider* values). Native-app token sign-in is
// separate; see [AuthService.Providers].
Providers []string `json:"providers"`
// ProviderLabels is what each provider's button should say, keyed by the
// same identifiers, so a deployment behind Authentik says so.
ProviderLabels map[string]string `json:"provider_labels,omitempty"`
// SelfHosted lets a client drop hosted-only affordances.
SelfHosted bool `json:"self_hosted"`
// BillingEnabled is false when the deployment runs without a billing
// provider: every feature is then unlocked and there is no trial or plan
// to show. SelfHosted alone does not imply it.
BillingEnabled bool `json:"billing_enabled"`
// SetupRequired is true while the instance has no accounts at all; claim
// it with [AuthService.Setup] before any sign-in can work.
SetupRequired bool `json:"setup_required"`
// InvitesRequired mirrors Registration == [RegistrationInviteOnly].
InvitesRequired bool `json:"invites_required"`
// DocsURL is where to send someone whose signup was refused by deployment
// policy.
DocsURL string `json:"docs_url"`
// WebsocketURL is the realtime gateway; empty when the instance runs no
// realtime service. AppURL is the dashboard origin, for building links to
// pages. Both are served here because on a self-hosted instance the host
// layout is whatever the operator chose.
WebsocketURL string `json:"websocket_url,omitempty"`
AppURL string `json:"app_url,omitempty"`
}
AuthConfig is what a deployment supports, so one client binary adapts to hosted and self-hosted backends instead of guessing. Everything here is public, non-secret configuration; read it before rendering a sign-in.
type AuthProvider ¶
type AuthProvider struct {
Enabled bool `json:"enabled"`
ClientID string `json:"client_id,omitempty"`
}
AuthProvider is one social sign-in option. The client id is public.
type AuthProviders ¶
type AuthProviders struct {
Apple AuthProvider `json:"apple"`
Google AuthProvider `json:"google"`
}
AuthProviders reports which social sign-in options the deployment supports, so one client binary adapts to hosted and self-hosted backends.
type AuthService ¶
type AuthService service
AuthService handles user sign-in and the session it produces: the email flow, browser SSO, the CLI device flow, two-factor verification, session management, the caller's own profile, notification preferences and device tokens. It also reads what the deployment supports (AuthService.Config) and, on a self-hosted instance, what version it runs (AuthService.Instance).
This is the credential path for anything an API key cannot reach — workspace governance, billing, the AI assistant. Sign in, then pass the returned Session.AccessToken to WithAccessToken (or wrap it in a TokenSource that refreshes it).
Sign-in is usually two steps: AuthService.Login emails a code and returns an opaque session handle, and AuthService.LoginConfirm exchanges the handle and code for tokens. Whether the code step happens is deployment policy (AuthConfig.LoginCode): with it off, or on a device the account has used before, the first call already carries the tokens, which is why it answers with an AuthStep rather than a bare handle. When the account has 2FA on, whichever call completes the sign-in returns Session.TwoFARequired with a Session.PendingToken to finish through AuthService.VerifyTwoFA.
func (*AuthService) ApproveCLIAuth ¶ added in v0.3.0
func (s *AuthService) ApproveCLIAuth(ctx context.Context, userCode, organizationID string, opts ...RequestOption) (*CLIAuthRequest, *Response, error)
ApproveCLIAuth approves a handshake and mints an ordinary API key into the given workspace — not necessarily the session's, because a member of several workspaces picks one on screen. An empty organizationID uses the session's workspace. The key shows up under Settings > API keys and the result's CLIAuthRequest.APIKeyID names it. This route is session-only and needs the manage-API-keys organization permission (OrgPermManageAPIKeys): an API key must not be able to mint another one this way. A code that is no longer pending answers 409.
func (*AuthService) BeginPasskeyLogin ¶
func (s *AuthService) BeginPasskeyLogin(ctx context.Context, opts ...RequestOption) (*PasskeyLoginChallenge, *Response, error)
BeginPasskeyLogin starts a discoverable passkey sign-in and returns the WebAuthn request options together with the handle to finish with. It needs no credentials: there is no account context until the assertion resolves, and the challenge and signature are the protection.
func (*AuthService) BeginPasskeyRegistration ¶
func (s *AuthService) BeginPasskeyRegistration(ctx context.Context, opts ...RequestOption) (json.RawMessage, *Response, error)
BeginPasskeyRegistration starts enrolling a passkey on the signed-in account and returns the WebAuthn creation options.
func (*AuthService) BeginSSO ¶ added in v0.3.0
func (s *AuthService) BeginSSO(ctx context.Context, provider string, opts ...RequestOption) (*SSORedirect, *Response, error)
BeginSSO starts a browser sign-in with one of the SSOProvider* providers listed in AuthConfig.Providers and returns the authorization URL to send the browser to. Keep the SSORedirect.Binding: the exchange needs it.
The provider sends the browser back to the API's callback, which redirects to the dashboard's /auth/sso page with a single-use "code" query parameter. Those callbacks are browser redirects, not JSON, so this SDK does not model them; collect the code from the redirect and pass it to AuthService.ExchangeSSO. A refused consent screen redirects back to the login page with no code.
func (*AuthService) CLIAuthRequest ¶ added in v0.3.0
func (s *AuthService) CLIAuthRequest(ctx context.Context, userCode string, opts ...RequestOption) (*CLIAuthRequest, *Response, error)
CLIAuthRequest describes a pending handshake by its user code, for an approval screen: which client is asking, from which machine, and for which scopes. This route is session-only.
func (*AuthService) CancelDeletion ¶
func (s *AuthService) CancelDeletion(ctx context.Context, reason string, opts ...RequestOption) (*Response, error)
CancelDeletion cancels a pending account deletion.
func (*AuthService) ChangePassword ¶
func (s *AuthService) ChangePassword(ctx context.Context, currentPassword, newPassword string, opts ...RequestOption) (*Response, error)
ChangePassword sets a new password, which requires the current one.
func (*AuthService) CompleteOnboarding ¶
func (s *AuthService) CompleteOnboarding(ctx context.Context, params *OnboardingParams, opts ...RequestOption) (*User, *Response, error)
CompleteOnboarding answers the first-run questions.
func (*AuthService) Config ¶ added in v0.3.0
func (s *AuthService) Config(ctx context.Context, opts ...RequestOption) (*AuthConfig, *Response, error)
Config reports what this deployment supports: which sign-in methods are on, whether a login code follows, whether signups are open, whether the instance still needs claiming. It needs no credentials and is the first call a sign-in screen should make.
func (*AuthService) ConfirmTwoFA ¶
func (s *AuthService) ConfirmTwoFA(ctx context.Context, code string, opts ...RequestOption) (*TwoFARecoveryCodes, *Response, error)
ConfirmTwoFA finishes setup with a code from the authenticator and returns the recovery codes, which are shown exactly once.
func (*AuthService) DangerZone ¶
func (s *AuthService) DangerZone(ctx context.Context, opts ...RequestOption) (*DangerZoneStatus, *Response, error)
DangerZone returns the account's deletion state and the confirmation phrase required to schedule one.
func (*AuthService) DeleteAvatar ¶
func (s *AuthService) DeleteAvatar(ctx context.Context, opts ...RequestOption) (*Response, error)
DeleteAvatar removes the caller's profile picture.
func (*AuthService) DeleteDeviceToken ¶
func (s *AuthService) DeleteDeviceToken(ctx context.Context, token string, opts ...RequestOption) (*Response, error)
DeleteDeviceToken unregisters a device from push notifications.
func (*AuthService) DeletePasskey ¶
func (s *AuthService) DeletePasskey(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeletePasskey removes a registered credential.
func (*AuthService) DenyCLIAuth ¶ added in v0.3.0
func (s *AuthService) DenyCLIAuth(ctx context.Context, userCode string, opts ...RequestOption) (*Response, error)
DenyCLIAuth declines a handshake; the polling client sees CLIAuthDenied. Nothing is created, so nothing is audited. This route is session-only and needs OrgPermManageAPIKeys.
func (*AuthService) DisableTwoFA ¶
func (s *AuthService) DisableTwoFA(ctx context.Context, code string, opts ...RequestOption) (*Response, error)
DisableTwoFA turns two-factor off. It requires a current code or a recovery code.
func (*AuthService) EnrollTwoFA ¶
func (s *AuthService) EnrollTwoFA(ctx context.Context, opts ...RequestOption) (*TwoFAEnrollment, *Response, error)
EnrollTwoFA begins two-factor setup and returns the shared secret. Confirm it with AuthService.ConfirmTwoFA before it takes effect.
func (*AuthService) ExchangeSSO ¶ added in v0.3.0
func (s *AuthService) ExchangeSSO(ctx context.Context, code, binding string, opts ...RequestOption) (*Session, *Response, error)
ExchangeSSO swaps the handoff code from a provider callback, together with the binding from AuthService.BeginSSO, for a session. The code is single use. A code presented without the binding of the browser that began the sign-in fails with code "sso_wrong_browser", by design: a forwarded handoff link cannot sign its recipient in. Two-factor applies here like everywhere else; see Session.TwoFARequired.
The route is POST /auth/sso/exchange; the server also keeps the older POST /auth/oidc/exchange as an alias for the same handler.
func (*AuthService) FinishPasskeyLogin ¶
func (s *AuthService) FinishPasskeyLogin(ctx context.Context, session string, assertion json.RawMessage, opts ...RequestOption) (*Session, *Response, error)
FinishPasskeyLogin completes a passkey sign-in with the handle from PasskeyLoginChallenge.Session and the authenticator's assertion, and returns the session. It is a single step with no emailed code; two-factor still applies (Session.TwoFARequired).
func (*AuthService) FinishPasskeyRegistration ¶
func (s *AuthService) FinishPasskeyRegistration(ctx context.Context, name string, attestation json.RawMessage, opts ...RequestOption) (*PasskeyCredential, *Response, error)
FinishPasskeyRegistration completes enrollment with the authenticator's attestation and returns the stored credential. Name is the label shown in the credential list; empty lets the server pick one.
func (*AuthService) Instance ¶ added in v0.3.0
func (s *AuthService) Instance(ctx context.Context, opts ...RequestOption) (*InstanceInfo, *Response, error)
Instance reports the running version of a self-hosted instance and whether a newer release exists. This route is session-only; any signed-in member may call it. A hosted deployment answers with SelfHosted false and nothing else.
func (*AuthService) Login ¶
func (s *AuthService) Login(ctx context.Context, params *LoginParams, opts ...RequestOption) (*AuthStep, *Response, error)
Login starts a password sign-in. Usually it emails a code and returns the session handle for AuthService.LoginConfirm; when the deployment's login-code policy does not demand one for this device, the returned AuthStep already carries the tokens. Branch on AuthStep.CodeRequired. It is refused when AuthConfig.PasswordLogin is false.
func (*AuthService) LoginConfirm ¶
func (s *AuthService) LoginConfirm(ctx context.Context, params *ConfirmParams, opts ...RequestOption) (*Session, *Response, error)
LoginConfirm exchanges the session handle and emailed code for tokens. When the account has two-factor enabled the result carries Session.TwoFARequired instead.
func (*AuthService) LoginWithApple ¶
func (s *AuthService) LoginWithApple(ctx context.Context, identityToken string, opts ...RequestOption) (*Session, *Response, error)
LoginWithApple exchanges an Apple-signed identity token for a session. The token's signature is the credential, so this needs no prior sign-in.
func (*AuthService) LoginWithGoogle ¶
func (s *AuthService) LoginWithGoogle(ctx context.Context, idToken string, opts ...RequestOption) (*Session, *Response, error)
LoginWithGoogle exchanges a Google-signed ID token for a session.
func (*AuthService) Logout ¶
func (s *AuthService) Logout(ctx context.Context, opts ...RequestOption) (*Response, error)
Logout revokes the current session.
func (*AuthService) LogoutAll ¶
func (s *AuthService) LogoutAll(ctx context.Context, opts ...RequestOption) (*Response, error)
LogoutAll revokes every session on the account, including this one.
func (*AuthService) MarkAllNotificationsRead ¶
func (s *AuthService) MarkAllNotificationsRead(ctx context.Context, opts ...RequestOption) (*Response, error)
MarkAllNotificationsRead marks the whole feed read.
func (*AuthService) MarkNotificationRead ¶
func (s *AuthService) MarkNotificationRead(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
MarkNotificationRead marks one notification read.
func (*AuthService) Me ¶
func (s *AuthService) Me(ctx context.Context, opts ...RequestOption) (*User, *Response, error)
Me returns the caller's own profile, including their folder, tag and category sets.
func (*AuthService) NotificationPreferences ¶
func (s *AuthService) NotificationPreferences(ctx context.Context, opts ...RequestOption) (*NotificationPreferencesResult, *Response, error)
NotificationPreferences returns the caller's notification configuration.
func (*AuthService) Notifications ¶
func (s *AuthService) Notifications(ctx context.Context, opts ...RequestOption) (*NotificationFeed, *Response, error)
Notifications returns the caller's in-app feed and unread count, newest first. The feed is capped at 50 entries unless a "limit" is given, and "unread=true" narrows it to what has not been read:
feed, _, err := client.Auth.Notifications(ctx,
warmbly.WithQueryParam("unread", "true"))
func (*AuthService) Passkeys ¶
func (s *AuthService) Passkeys(ctx context.Context, opts ...RequestOption) ([]PasskeyCredential, *Response, error)
Passkeys returns the account's registered WebAuthn credentials.
func (*AuthService) PollCLIAuth ¶ added in v0.3.0
func (s *AuthService) PollCLIAuth(ctx context.Context, deviceCode string, opts ...RequestOption) (*CLIAuthPoll, *Response, error)
PollCLIAuth asks once whether a member has decided. The answer is CLIAuthPending until they do, then CLIAuthApproved carrying the minted key exactly once (a later poll finds the code spent), or CLIAuthDenied. An unknown or expired device code is a 404 (ErrNotFound): the two are indistinguishable on purpose, so a poller cannot probe for live handshakes. Respect CLIAuthHandshake.Interval between polls; polling faster is rate limited per IP.
func (*AuthService) Providers ¶
func (s *AuthService) Providers(ctx context.Context, opts ...RequestOption) (*AuthProviders, *Response, error)
Providers reports which social sign-in options this deployment supports. It needs no credentials.
func (*AuthService) Refresh ¶
func (s *AuthService) Refresh(ctx context.Context, refreshToken string, opts ...RequestOption) (*Session, *Response, error)
Refresh exchanges a refresh token for a fresh token pair. See [RefreshTokenSource] to have the client do this automatically.
func (*AuthService) Register ¶
func (s *AuthService) Register(ctx context.Context, params *LoginParams, opts ...RequestOption) (*AuthStep, *Response, error)
Register starts account creation. With email verification on it emails a code and returns the handle for AuthService.RegisterConfirm; otherwise the account is created at once and the AuthStep carries its session. On an invite-only deployment LoginParams.Invite is required; see the codes it documents.
func (*AuthService) RegisterConfirm ¶
func (s *AuthService) RegisterConfirm(ctx context.Context, params *ConfirmParams, opts ...RequestOption) (*AuthStep, *Response, error)
RegisterConfirm completes account creation with the emailed code and signs the new account in: the result's AuthStep.Token is the session. It is nil only when the account was created but could not be signed in on the spot, in which case AuthService.Login works.
func (*AuthService) RegisterDeviceToken ¶
func (s *AuthService) RegisterDeviceToken(ctx context.Context, token, platform, environment string, opts ...RequestOption) (*Response, error)
RegisterDeviceToken registers a device for push notifications. The token is an APNs token (hex); platform must be "ios" or empty, and environment "production", "development" or empty, which defaults to production. Registering the same token again is harmless: it refreshes the record rather than creating a second one. The registration is not readable back — there is no route that lists a user's devices.
func (*AuthService) RenamePasskey ¶
func (s *AuthService) RenamePasskey(ctx context.Context, id, name string, opts ...RequestOption) (*PasskeyCredential, *Response, error)
RenamePasskey relabels a registered credential.
func (*AuthService) ResetPassword ¶
func (s *AuthService) ResetPassword(ctx context.Context, email, turnstile string, opts ...RequestOption) (*Response, error)
ResetPassword emails a password-reset code. It answers the same way whether or not the address has an account.
func (*AuthService) ResetPasswordConfirm ¶
func (s *AuthService) ResetPasswordConfirm(ctx context.Context, session, password, turnstile string, opts ...RequestOption) (*Response, error)
ResetPasswordConfirm sets a new password using the emailed session handle.
func (*AuthService) RevokeOtherSessions ¶
func (s *AuthService) RevokeOtherSessions(ctx context.Context, opts ...RequestOption) (*Response, error)
RevokeOtherSessions signs out every session except the current one.
func (*AuthService) RevokeSession ¶
func (s *AuthService) RevokeSession(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
RevokeSession signs one session out.
func (*AuthService) ScheduleDeletion ¶
func (s *AuthService) ScheduleDeletion(ctx context.Context, params *ScheduleDeletionParams, opts ...RequestOption) (*ScheduledDeletion, *Response, error)
ScheduleDeletion schedules the caller's own account for a delayed hard delete. Confirmation must match DangerZoneStatus.ConfirmationHint, which for an account is their email address.
func (*AuthService) Sessions ¶
func (s *AuthService) Sessions(ctx context.Context, opts ...RequestOption) ([]UserSession, *Response, error)
Sessions returns the account's active sessions.
func (*AuthService) SetUndoSendSeconds ¶
func (s *AuthService) SetUndoSendSeconds(ctx context.Context, seconds int, opts ...RequestOption) (*Response, error)
SetUndoSendSeconds sets how long an instant send is held, and stays cancelable, before it leaves. The server bounds the value.
func (*AuthService) Setup ¶ added in v0.3.0
func (s *AuthService) Setup(ctx context.Context, params *SetupParams, opts ...RequestOption) (*Session, *Response, error)
Setup claims a fresh self-hosted instance: it exchanges the one-time setup token for the owner account and returns its session, so there is no second sign-in. It needs no credentials — the token is the protection — and works only while AuthConfig.SetupRequired is true. An invalid, used or expired token fails with code "setup_token_invalid"; an instance that already has an account fails with "setup_already_complete".
func (*AuthService) StartCLIAuth ¶ added in v0.3.0
func (s *AuthService) StartCLIAuth(ctx context.Context, params *CLIAuthStartParams, opts ...RequestOption) (*CLIAuthHandshake, *Response, error)
StartCLIAuth opens a device-flow handshake for a client that holds no credential yet. Show the person CLIAuthHandshake.UserCode, open CLIAuthHandshake.VerificationURIComplete, then poll with AuthService.PollCLIAuth or let AuthService.WaitForCLIAuth do it. It needs no credentials and is per-IP rate limited; the handshake expires after CLIAuthHandshake.ExpiresIn seconds. A deployment without CLI sign-in answers 501.
func (*AuthService) TwoFAStatus ¶
func (s *AuthService) TwoFAStatus(ctx context.Context, opts ...RequestOption) (*TwoFAStatus, *Response, error)
TwoFAStatus reports whether two-factor is enabled on the account.
func (*AuthService) UpdateNotificationPreferences ¶
func (s *AuthService) UpdateNotificationPreferences(ctx context.Context, prefs *NotificationPreferences, opts ...RequestOption) (*NotificationPreferencesResult, *Response, error)
UpdateNotificationPreferences replaces the caller's notification configuration.
func (*AuthService) UpdateProfile ¶
func (s *AuthService) UpdateProfile(ctx context.Context, params *ProfileUpdateParams, opts ...RequestOption) (*User, *Response, error)
UpdateProfile changes the caller's name.
func (*AuthService) UploadAvatar ¶
func (s *AuthService) UploadAvatar(ctx context.Context, file *FileUpload, opts ...RequestOption) (string, *Response, error)
UploadAvatar sets the caller's profile picture and returns the URL it is now served from. The image must be a PNG or JPEG, at most 2 MB and 1024 pixels on a side; anything else is refused. The previous avatar is deleted.
func (*AuthService) VerifyTwoFA ¶
func (s *AuthService) VerifyTwoFA(ctx context.Context, pendingToken, code string, opts ...RequestOption) (*Session, *Response, error)
VerifyTwoFA completes a sign-in that stopped at the two-factor step, using the pending token from AuthService.LoginConfirm and a TOTP or recovery code.
func (*AuthService) WaitForCLIAuth ¶ added in v0.3.0
func (s *AuthService) WaitForCLIAuth(ctx context.Context, hs *CLIAuthHandshake, opts ...RequestOption) (*CLIAuthPoll, error)
WaitForCLIAuth polls a handshake until a member decides, the handshake expires, or ctx is done. It sleeps CLIAuthHandshake.Interval between polls (five seconds when the server sent none) and, when the server asks it to slow down with a 429, waits the Retry-After it was given — or five more seconds — before continuing rather than failing.
On approval it returns the poll carrying the key. A denial returns ErrCLIAuthDenied; an expired handshake surfaces as ErrNotFound from the poll; and a canceled context returns its error. Typical use:
hs, _, err := client.Auth.StartCLIAuth(ctx, &warmbly.CLIAuthStartParams{Hostname: host})
fmt.Println("Approve at", hs.VerificationURIComplete)
grant, err := client.Auth.WaitForCLIAuth(ctx, hs)
// grant.Token is the API key
type AuthStep ¶ added in v0.3.0
type AuthStep struct {
// Session is the opaque handle for the confirm step. Empty when the flow
// already finished.
Session string `json:"session,omitempty"`
// CodeRequired is true when an emailed code must be confirmed next.
CodeRequired bool `json:"code_required"`
// Token is the session when the flow finished in one step. It is nil while
// a code is still required, and also nil after a completed signup that
// could not be signed in immediately: the account exists, so sign in with
// [AuthService.Login].
Token *Session `json:"token,omitempty"`
// TwoFARequired, PendingToken and ExpiresIn are the 2FA challenge, set
// instead of Token when the flow finished but the account has two-factor
// on. Finish with [AuthService.VerifyTwoFA].
TwoFARequired bool `json:"two_fa_required,omitempty"`
PendingToken string `json:"pending_token,omitempty"`
ExpiresIn int `json:"expires_in,omitempty"`
}
AuthStep is the outcome of the first step of a sign-in or signup. Either another step is needed — CodeRequired is true and Session is the handle to pass to the confirm call — or the flow finished in one call and Token holds the session (with the usual 2FA challenge fields when the account has two-factor on).
A deployment decides which: an emailed login code can be off entirely, or skipped on a device the account has signed in from before; a signup skips verification when the deployment does not require it or cannot deliver mail. Branch on CodeRequired rather than assuming the code step.
type Authenticator ¶
type Authenticator interface {
// contains filtered or unexported methods
}
Authenticator attaches credentials to an outgoing request. The SDK ships with API-key and OAuth access-token authenticators; you may also supply your own via WithAuthenticator.
type AuthenticatorFunc ¶
AuthenticatorFunc adapts an ordinary function to an Authenticator.
type AuthorizeParams ¶
type AuthorizeParams struct {
// ResponseType is "code".
ResponseType string `json:"response_type"`
ClientID string `json:"client_id"`
RedirectURI string `json:"redirect_uri"`
// Scope is the space-delimited set being granted.
Scope string `json:"scope"`
State string `json:"state"`
// CodeChallenge and CodeChallengeMethod carry PKCE, which is required for
// a public client.
CodeChallenge string `json:"code_challenge,omitempty"`
CodeChallengeMethod string `json:"code_challenge_method,omitempty"`
}
AuthorizeParams approves a consent request and mints an authorization code. The fields mirror the query parameters the application sent the user with.
type AuthorizedApp ¶
type AuthorizedApp struct {
ApplicationID string `json:"application_id"`
Name string `json:"name"`
LogoURL string `json:"logo_url,omitempty"`
WebsiteURL string `json:"website_url,omitempty"`
// Scopes is what was actually granted, which may be less than the app
// asked for.
Scopes uint64 `json:"scopes"`
AuthorizedAt time.Time `json:"authorized_at"`
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
}
AuthorizedApp is an application a user has granted access to their workspace.
type Automation ¶
type Automation struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
// TriggerEvent is the event key that starts the run: a Trigger* constant
// or any Event* constant.
TriggerEvent string `json:"trigger_event"`
// Filter narrows which occurrences of the trigger event actually run it.
Filter json.RawMessage `json:"filter,omitempty"`
Graph AutomationGraph `json:"graph"`
// InboundURL is the public POST URL that fires the automation, set only
// when TriggerEvent is [TriggerInboundWebhook]. It embeds a per-automation
// secret, so treat it as a credential.
InboundURL string `json:"inbound_url,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Automation is a trigger plus the graph that runs when it fires.
type AutomationCondition ¶
type AutomationCondition struct {
// Field is one of the Condition* constants.
Field string `json:"field"`
// Key names the event-data key to read for [ConditionField].
Key string `json:"key,omitempty"`
// Operator is one of the ConditionOp* constants.
Operator string `json:"operator"`
Value any `json:"value,omitempty"`
// Expression is the Go-template predicate for [ConditionExpression].
Expression string `json:"expression,omitempty"`
// Prompt is the yes/no question for [ConditionAI].
Prompt string `json:"prompt,omitempty"`
}
AutomationCondition is a condition node's test. Field picks the kind of test; the other fields apply according to the Condition* constant.
type AutomationCreateParams ¶
type AutomationCreateParams struct {
Name string `json:"name"`
Enabled bool `json:"enabled"`
// TriggerEvent is the event key that starts it.
TriggerEvent string `json:"trigger_event"`
Filter json.RawMessage `json:"filter,omitempty"`
Graph AutomationGraph `json:"graph"`
}
AutomationCreateParams creates an automation.
type AutomationEdge ¶
type AutomationEdge struct {
ID string `json:"id"`
Source string `json:"source"`
Target string `json:"target"`
When string `json:"when,omitempty"`
}
AutomationEdge connects two nodes. When is the branch label; see the EdgeWhen* constants. The graph may not contain a cycle: a flow that loops back on itself is a 400 when saved.
type AutomationGraph ¶
type AutomationGraph struct {
Nodes []AutomationNode `json:"nodes"`
Edges []AutomationEdge `json:"edges"`
}
AutomationGraph is the node graph, as drawn on the builder canvas.
type AutomationNode ¶
type AutomationNode struct {
ID string `json:"id"`
// Type is [NodeTrigger], [NodeCondition], [NodeAction] or [NodeStop].
Type string `json:"type"`
// Action is the action identifier for an action node; see the Action*
// constants.
Action string `json:"action,omitempty"`
// ConnectionID is the integration a provider action runs against. The
// built-in "warmbly." actions leave it nil.
ConnectionID *string `json:"connection_id,omitempty"`
// Config is the action's parameters. Its shape depends on Action; the
// built-in [UpsertContactConfig] and [AddToCampaignConfig] render into it,
// and the server validates it when the automation is saved (400).
Config json.RawMessage `json:"config,omitempty"`
// Condition is the test a condition node applies.
Condition *AutomationCondition `json:"condition,omitempty"`
// X and Y are the node's canvas coordinates.
X float64 `json:"x"`
Y float64 `json:"y"`
}
AutomationNode is one step. Which fields matter depends on Type.
type AutomationNodeResult ¶
type AutomationNodeResult struct {
NodeID string `json:"node_id"`
// Type is [NodeTrigger], [NodeCondition] or [NodeAction].
Type string `json:"type"`
Action string `json:"action,omitempty"`
Label string `json:"label,omitempty"`
// Status is one of the NodeStatus* constants.
Status string `json:"status"`
Error string `json:"error,omitempty"`
// Preview is a JSON object of what the action sent or would send: the
// rendered templates of a dry run, plus run-time output such as the
// contact_id and contact_created of an [ActionUpsertContact] node.
Preview json.RawMessage `json:"preview,omitempty"`
}
AutomationNodeResult is what one node did during a run or a dry run.
type AutomationRun ¶
type AutomationRun struct {
ID string `json:"id"`
AutomationID string `json:"automation_id"`
OrganizationID string `json:"organization_id,omitempty"`
TriggerEvent string `json:"trigger_event"`
// Status is [AutomationRunning], [AutomationSuccess] or [AutomationError].
Status string `json:"status"`
NodeResults []AutomationNodeResult `json:"node_results"`
ErrorDetail string `json:"error_detail,omitempty"`
StartedAt time.Time `json:"started_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
}
AutomationRun is one execution, with a per-node trace.
type AutomationService ¶
type AutomationService service
AutomationService manages automations: a trigger event plus a graph of condition and action nodes that runs across connected integrations and the built-in Warmbly actions.
An automation can also be triggered from outside Warmbly. Each one whose trigger is TriggerInboundWebhook gets a token-addressed inbound URL (Automation.InboundURL) that runs it with the POSTed JSON body as the event payload.
Chains are bounded. Everything an action does (a contact it creates, a deal it opens, an automation it launches) fires events one hop deeper, and past MaxAutomationDepth hops those events still reach webhooks but run no more automations, so "on contact created, create a contact" cannot loop.
func (*AutomationService) Create ¶
func (s *AutomationService) Create(ctx context.Context, params *AutomationCreateParams, opts ...RequestOption) (*Automation, *Response, error)
Create creates an automation. Node configs are validated, so a built-in action missing its required field fails here with a 400.
func (*AutomationService) Delete ¶
func (s *AutomationService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete removes an automation. It fails with a 409 while a campaign step still runs it; remove the step first.
func (*AutomationService) DryRun ¶ added in v0.3.0
func (s *AutomationService) DryRun(ctx context.Context, id string, params *AutomationTestParams, opts ...RequestOption) (*AutomationTestResult, *Response, error)
DryRun tests an automation without side effects. Conditions evaluate for real and action nodes are previewed rather than executed, with one exception: AI nodes run for real, and are charged, so the trace shows the model's actual output.
func (*AutomationService) Get ¶
func (s *AutomationService) Get(ctx context.Context, id string, opts ...RequestOption) (*Automation, *Response, error)
Get retrieves a single automation, including its graph.
func (*AutomationService) List ¶
func (s *AutomationService) List(ctx context.Context, opts ...RequestOption) ([]Automation, *Response, error)
List returns the workspace's automations.
func (*AutomationService) Runs ¶
func (s *AutomationService) Runs(ctx context.Context, id string, limit int, opts ...RequestOption) ([]AutomationRun, *Response, error)
Runs returns an automation's recent runs, newest first. A limit of 0 uses the server default of 50.
func (*AutomationService) Test ¶
func (s *AutomationService) Test(ctx context.Context, id string, data any, opts ...RequestOption) (*AutomationTestResult, *Response, error)
Test dry-runs an automation against sample event data and returns the trace. Pass nil data to use the server's sample for the trigger. It is AutomationService.DryRun without the option to skip nodes.
func (*AutomationService) Update ¶
func (s *AutomationService) Update(ctx context.Context, id string, params *AutomationUpdateParams, opts ...RequestOption) (*Automation, *Response, error)
Update replaces an automation's definition. See AutomationUpdateParams.
func (*AutomationService) UpdateLayout ¶
func (s *AutomationService) UpdateLayout(ctx context.Context, id string, positions []NodePosition, opts ...RequestOption) (*Response, error)
UpdateLayout persists node coordinates only. It is cosmetic: unaudited, last-write-wins, and safe to call continuously as nodes are dragged. At most 1,000 positions are accepted per call.
type AutomationTestParams ¶ added in v0.3.0
type AutomationTestParams struct {
// Data is the sample event payload. Leave it nil to let the server build
// one from the trigger.
Data any `json:"data,omitempty"`
// SkipNodeIDs are action nodes to leave out of this test. They are
// recorded as [NodeStatusSkipped] and never previewed, but the walk still
// follows their edges so later steps are shown.
SkipNodeIDs []string `json:"skip_node_ids,omitempty"`
}
AutomationTestParams configures a dry run.
type AutomationTestResult ¶
type AutomationTestResult struct {
Trace []AutomationNodeResult `json:"trace"`
Data json.RawMessage `json:"data"`
}
AutomationTestResult is a dry run: the node-by-node trace plus the event data it ran against, including anything the nodes wrote into it.
type AutomationUpdateParams ¶
type AutomationUpdateParams = AutomationCreateParams
AutomationUpdateParams replaces an automation's definition. Unlike most update params these are not merged: the API rewrites the name, enabled flag, trigger, filter and node graph from what you send, so send the complete desired state. Read the current one with AutomationService.Get first if you only mean to change part of it.
type BillingService ¶
type BillingService service
BillingService reads and changes the workspace's subscription, plan, AI credit balance and spend controls, and the referral program.
These routes are session-only and gated on the manage-billing permission, so they need a session token rather than an API key. On a self-hosted deployment with billing disabled they may be absent entirely.
func (*BillingService) AppliedDiscounts ¶
func (s *BillingService) AppliedDiscounts(ctx context.Context, opts ...RequestOption) ([]DiscountRedemption, *Response, error)
AppliedDiscounts returns the promotions redeemed on the workspace, most recent first. It is not paginated: the server answers with its most recent 50.
func (*BillingService) BuyCredits ¶
func (s *BillingService) BuyCredits(ctx context.Context, pack, successURL, cancelURL string, opts ...RequestOption) (*CheckoutSession, *Response, error)
BuyCredits starts a hosted checkout for a top-up pack (a CreditPack.Key from CreditBalance.Packs). It requires an active paid plan; all three arguments are required.
func (*BillingService) Cancel ¶
func (s *BillingService) Cancel(ctx context.Context, atPeriodEnd bool, opts ...RequestOption) (*Response, error)
Cancel schedules the subscription to lapse at the end of the current period (atPeriodEnd true), or clears a cancellation that was already scheduled so it renews again (atPeriodEnd false). Either way the workspace keeps its plan until the period actually ends. It needs an active provider subscription; a workspace that never had one is refused.
func (*BillingService) ChangePlan ¶
func (s *BillingService) ChangePlan(ctx context.Context, params *ChangePlanParams, opts ...RequestOption) (*Subscription, *Response, error)
ChangePlan moves the workspace to a different plan and returns the updated subscription. It needs the manage-billing organization permission.
func (*BillingService) Checkout ¶
func (s *BillingService) Checkout(ctx context.Context, params *CheckoutParams, opts ...RequestOption) (*CheckoutSession, *Response, error)
Checkout starts a hosted checkout for a plan and returns the URL to send the user to.
func (*BillingService) CreditSettings ¶
func (s *BillingService) CreditSettings(ctx context.Context, opts ...RequestOption) (*CreditSettings, *Response, error)
CreditSettings returns the workspace's AI spend controls.
func (*BillingService) CreditTransactions ¶
func (s *BillingService) CreditTransactions(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[CreditTransaction], error)
CreditTransactions returns a page of the credit ledger, newest first.
func (*BillingService) CreditUsage ¶
func (s *BillingService) CreditUsage(ctx context.Context, days int, opts ...RequestOption) (*CreditUsage, *Response, error)
CreditUsage returns AI spend over the last days, from 1 to 90. Zero uses the server default.
func (*BillingService) Credits ¶
func (s *BillingService) Credits(ctx context.Context, opts ...RequestOption) (*CreditBalance, *Response, error)
Credits returns the workspace's AI credit position. Check CreditBalance.Unlimited first: a deployment without billing meters nothing.
func (*BillingService) EnsureReferralCode ¶
func (s *BillingService) EnsureReferralCode(ctx context.Context, opts ...RequestOption) (*ReferralCode, *Response, error)
EnsureReferralCode mints the workspace's referral code if it does not have one yet, and returns it either way. It is idempotent: a workspace has one code, and calling this again returns the same one. For the shareable link and the running totals, read BillingService.Referral.
func (*BillingService) EnterpriseInquiry ¶
func (s *BillingService) EnterpriseInquiry(ctx context.Context, params *EnterpriseInquiryParams, opts ...RequestOption) (string, *Response, error)
EnterpriseInquiry asks the sales team to get in touch about enterprise pricing and returns the inquiry's id.
func (*BillingService) Features ¶
func (s *BillingService) Features(ctx context.Context, opts ...RequestOption) (*FeatureStatus, *Response, error)
Features returns the capability gates a client should check before offering an action.
func (*BillingService) Get ¶
func (s *BillingService) Get(ctx context.Context, opts ...RequestOption) (*Subscription, *Response, error)
Get returns the workspace's subscription.
func (*BillingService) Limits ¶
func (s *BillingService) Limits(ctx context.Context, opts ...RequestOption) (*SubscriptionWithLimits, *Response, error)
Limits returns the subscription together with the realtime rate limits its plan carries. For the plan-gate view (trial state, daily send cap) see BillingService.Features.
func (*BillingService) Portal ¶
func (s *BillingService) Portal(ctx context.Context, returnURL string, opts ...RequestOption) (string, *Response, error)
Portal opens the payment provider's billing portal and returns its URL. returnURL, where the portal sends the user back, is required.
func (*BillingService) PreviewPlanChange ¶
func (s *BillingService) PreviewPlanChange(ctx context.Context, newPlanID string, opts ...RequestOption) (*PlanChangePreview, *Response, error)
PreviewPlanChange returns the proration moving to newPlanID would produce, without making the change. It needs the manage-billing organization permission.
func (*BillingService) Referral ¶
func (s *BillingService) Referral(ctx context.Context, opts ...RequestOption) (*ReferralSummary, *Response, error)
Referral returns the workspace's referral summary.
func (*BillingService) ReferralAttributions ¶
func (s *BillingService) ReferralAttributions(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[ReferralAttribution], error)
ReferralAttributions returns a page of the workspaces referred, with where each reward stands.
func (*BillingService) ReferralEarnings ¶
func (s *BillingService) ReferralEarnings(ctx context.Context, params *ListOptions, opts ...RequestOption) (*Page[ReferralEarning], error)
ReferralEarnings returns a page of the referral credit ledger.
func (*BillingService) Trial ¶
func (s *BillingService) Trial(ctx context.Context, opts ...RequestOption) (*TrialStatus, *Response, error)
Trial returns where the workspace stands in its free trial.
func (*BillingService) UpdateCreditSettings ¶
func (s *BillingService) UpdateCreditSettings(ctx context.Context, params *CreditSettingsParams, opts ...RequestOption) (*CreditSettings, *Response, error)
UpdateCreditSettings saves the AI spend controls.
func (*BillingService) ValidateDiscount ¶
func (s *BillingService) ValidateDiscount(ctx context.Context, code, planID string, opts ...RequestOption) (*DiscountPreview, *Response, error)
ValidateDiscount checks a promotion code and reports what it would do. Name a planID to get the amounts it works out to on that plan; pass "" to just check the code. A code that cannot be used is not an error: the preview comes back with DiscountPreview.Valid false and a reason.
type BouncePipelineSettings ¶
type BouncePipelineSettings struct {
Enabled bool `json:"enabled"`
AutoSuppressOnBounce bool `json:"auto_suppress_on_bounce"`
AutoSuppressOnComplaint bool `json:"auto_suppress_on_complaint"`
AutoSuppressOnUnsubscribe bool `json:"auto_suppress_on_unsubscribe"`
AutoPauseCampaignOnSpike bool `json:"auto_pause_campaign_on_spike"`
// PauseBounceRateThreshold and PauseComplaintRateThreshold are rates in
// [0,1] at which a campaign is paused.
PauseBounceRateThreshold float64 `json:"pause_bounce_rate_threshold"`
PauseComplaintRateThreshold float64 `json:"pause_complaint_rate_threshold"`
}
BouncePipelineSettings controls automatic suppression and the circuit breaker that pauses a campaign when bounces or complaints spike.
type BulkTagParams ¶
type BulkTagParams struct {
EmailIDs []string `json:"email_ids"`
AddTags []string `json:"add_tags,omitempty"`
RemoveTags []string `json:"remove_tags,omitempty"`
}
BulkTagParams adds and removes tags across many mailboxes at once. Mailbox and tag ids the caller cannot see are ignored rather than failing the batch, and the operation is set-based, so retries are naturally safe.
type BulkTagResult ¶
type BulkTagResult struct {
Updated int `json:"updated"`
}
BulkTagResult reports how many mailboxes the tag change touched.
type CLIAuthHandshake ¶ added in v0.3.0
type CLIAuthHandshake struct {
// DeviceCode is the secret this client keeps and polls with.
DeviceCode string `json:"device_code"`
// UserCode is what to show the person: eight unambiguous characters they
// match against the approval screen.
UserCode string `json:"user_code"`
// VerificationURI is the approval page; VerificationURIComplete carries
// the code already, so opening it needs no typing.
VerificationURI string `json:"verification_uri"`
VerificationURIComplete string `json:"verification_uri_complete"`
// ExpiresIn is the handshake's lifetime in seconds; Interval is how many
// seconds to wait between polls.
ExpiresIn int `json:"expires_in"`
Interval int `json:"interval"`
}
CLIAuthHandshake is an open device-flow handshake, shaped like RFC 8628 so a generic device-flow client works against it.
type CLIAuthPoll ¶ added in v0.3.0
type CLIAuthPoll struct {
// Status is [CLIAuthPending], [CLIAuthApproved] or [CLIAuthDenied].
Status string `json:"status"`
// Token is the minted API key (prefixed "wmbly_"). It is shown here and
// never again: store it before returning.
Token string `json:"token,omitempty"`
// APIKeyID identifies the key under Settings > API keys, which is where
// it can be revoked (or with [APIKeyService.RevokeSelf]).
APIKeyID *string `json:"api_key_id,omitempty"`
// Scopes is the granted permission mask; ScopeNames the same as names.
Scopes uint64 `json:"scopes,omitempty"`
ScopeNames []string `json:"scope_names,omitempty"`
// The signed-in identity, for labeling the credential.
UserID *string `json:"user_id,omitempty"`
UserEmail string `json:"user_email,omitempty"`
UserName string `json:"user_name,omitempty"`
OrganizationID *string `json:"organization_id,omitempty"`
OrganizationName string `json:"organization_name,omitempty"`
}
CLIAuthPoll answers one poll. Status is the only field always set; the key fields arrive exactly once, on the poll that finds the code approved.
type CLIAuthRequest ¶ added in v0.3.0
type CLIAuthRequest struct {
ID string `json:"id"`
UserCode string `json:"user_code"`
ClientName string `json:"client_name"`
Hostname string `json:"hostname"`
CLIVersion string `json:"cli_version"`
Scopes uint64 `json:"scopes"`
ScopeNames []string `json:"scope_names"`
// Status is one of the CLIAuth* constants.
Status string `json:"status"`
// OrganizationID is the workspace the key was minted in, once approved.
OrganizationID *string `json:"organization_id,omitempty"`
// APIKeyID is set on the approval response only: the key that was minted.
APIKeyID *string `json:"api_key_id,omitempty"`
ExpiresAt time.Time `json:"expires_at"`
CreatedAt time.Time `json:"created_at"`
}
CLIAuthRequest is what the approving member is shown before deciding: who is asking, from where, and for which scopes.
type CLIAuthStartParams ¶ added in v0.3.0
type CLIAuthStartParams struct {
ClientName string `json:"client_name,omitempty"`
Hostname string `json:"hostname,omitempty"`
CLIVersion string `json:"cli_version,omitempty"`
Scopes uint64 `json:"scopes,omitempty"`
}
CLIAuthStartParams opens a device-flow handshake. Everything but Scopes is display-only: it is what the approving member sees. Scopes is the API permission mask the minted key will hold (the Perm* constants); zero asks for the server default.
type CRMService ¶
type CRMService service
CRMService manages the built-in CRM: deal pipelines and their stages, deals, and the task board that hangs off contacts and deals.
The deal and task lists come in two shapes. The plain List methods are cursor pages for straightforward browsing; the Search methods take a faceted filter body and are aggregated server-side, so a total or a per-stage sum is a true count over the whole matching set rather than a reduce over one page.
func (*CRMService) CreateDeal ¶
func (s *CRMService) CreateDeal(ctx context.Context, params *DealCreateParams, opts ...RequestOption) (*Deal, *Response, error)
CreateDeal opens a new deal.
func (*CRMService) CreatePipeline ¶
func (s *CRMService) CreatePipeline(ctx context.Context, params *PipelineCreateParams, opts ...RequestOption) (*Pipeline, *Response, error)
CreatePipeline creates a pipeline, optionally seeding its stages.
func (*CRMService) CreateStage ¶
func (s *CRMService) CreateStage(ctx context.Context, pipelineID string, params *StageCreateParams, opts ...RequestOption) (*PipelineStage, *Response, error)
CreateStage appends a stage to a pipeline.
func (*CRMService) CreateTask ¶
func (s *CRMService) CreateTask(ctx context.Context, params *CRMTaskCreateParams, opts ...RequestOption) (*CRMTask, *Response, error)
CreateTask opens a new CRM task.
func (*CRMService) CreateTaskType ¶
func (s *CRMService) CreateTaskType(ctx context.Context, params *TaskTypeCreateParams, opts ...RequestOption) (*CRMTaskType, *Response, error)
CreateTaskType adds a task type.
func (*CRMService) DealsSummary ¶
func (s *CRMService) DealsSummary(ctx context.Context, params *DealSearchParams, opts ...RequestOption) (*DealsSummary, *Response, error)
DealsSummary aggregates every deal matching the same filter a search takes.
func (*CRMService) DeleteDeal ¶
func (s *CRMService) DeleteDeal(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeleteDeal removes a deal.
func (*CRMService) DeletePipeline ¶
func (s *CRMService) DeletePipeline(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeletePipeline removes a pipeline.
func (*CRMService) DeleteStage ¶
func (s *CRMService) DeleteStage(ctx context.Context, pipelineID, stageID string, opts ...RequestOption) (*Response, error)
DeleteStage removes a pipeline stage.
func (*CRMService) DeleteTask ¶
func (s *CRMService) DeleteTask(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeleteTask removes a CRM task.
func (*CRMService) DeleteTaskType ¶
func (s *CRMService) DeleteTaskType(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeleteTaskType removes a task type. Tasks that used it keep its name.
func (*CRMService) GetDeal ¶
func (s *CRMService) GetDeal(ctx context.Context, id string, opts ...RequestOption) (*Deal, *Response, error)
GetDeal retrieves a single deal.
func (*CRMService) GetPipeline ¶
func (s *CRMService) GetPipeline(ctx context.Context, id string, opts ...RequestOption) (*Pipeline, *Response, error)
GetPipeline retrieves a pipeline and its stages.
func (*CRMService) GetTask ¶
func (s *CRMService) GetTask(ctx context.Context, id string, opts ...RequestOption) (*CRMTask, *Response, error)
GetTask retrieves a single CRM task.
func (*CRMService) ListDeals ¶
func (s *CRMService) ListDeals(ctx context.Context, params *DealListParams, opts ...RequestOption) (*Page[Deal], error)
ListDeals returns a page of deals, optionally narrowed to one pipeline, stage or status. Rows carry their joined contact and stage.
func (*CRMService) ListPipelines ¶
func (s *CRMService) ListPipelines(ctx context.Context, opts ...RequestOption) ([]Pipeline, *Response, error)
ListPipelines returns the organization's pipelines with their stages.
func (*CRMService) ListTaskTypes ¶
func (s *CRMService) ListTaskTypes(ctx context.Context, opts ...RequestOption) ([]CRMTaskType, *Response, error)
ListTaskTypes returns the organization's task types. The first read seeds a usable default set.
func (*CRMService) ListTasks ¶
func (s *CRMService) ListTasks(ctx context.Context, params *CRMTaskListParams, opts ...RequestOption) (*Page[CRMTask], error)
ListTasks returns a page of CRM tasks, optionally narrowed to one contact, deal, assignee or status.
func (*CRMService) SearchDeals ¶
func (s *CRMService) SearchDeals(ctx context.Context, params *DealSearchParams, opts ...RequestOption) (*Page[Deal], error)
SearchDeals returns a page of deals matching a faceted filter. Its page limit is capped at 200, twice what CRMService.ListDeals allows, and Pagination.Total is an exact count over the whole matching set.
func (*CRMService) SearchTasks ¶
func (s *CRMService) SearchTasks(ctx context.Context, params *TaskSearchParams, opts ...RequestOption) (*Page[CRMTask], error)
SearchTasks returns a page of tasks matching a faceted filter. Its page limit is capped at 200, twice what CRMService.ListTasks allows, and Pagination.Total is an exact count over the whole matching set.
func (*CRMService) TasksSummary ¶
func (s *CRMService) TasksSummary(ctx context.Context, params *TaskSearchParams, opts ...RequestOption) (*TasksSummary, *Response, error)
TasksSummary aggregates every task matching the same filter a search takes.
func (*CRMService) UpdateDeal ¶
func (s *CRMService) UpdateDeal(ctx context.Context, id string, params *DealUpdateParams, opts ...RequestOption) (*Deal, *Response, error)
UpdateDeal modifies a deal, including moving it between stages or closing it.
func (*CRMService) UpdatePipeline ¶
func (s *CRMService) UpdatePipeline(ctx context.Context, id string, params *PipelineUpdateParams, opts ...RequestOption) (*Pipeline, *Response, error)
UpdatePipeline renames a pipeline.
func (*CRMService) UpdateStage ¶
func (s *CRMService) UpdateStage(ctx context.Context, pipelineID, stageID string, params *StageUpdateParams, opts ...RequestOption) (*PipelineStage, *Response, error)
UpdateStage modifies a pipeline stage.
func (*CRMService) UpdateTask ¶
func (s *CRMService) UpdateTask(ctx context.Context, id string, params *CRMTaskUpdateParams, opts ...RequestOption) (*CRMTask, *Response, error)
UpdateTask modifies a CRM task.
func (*CRMService) UpdateTaskType ¶
func (s *CRMService) UpdateTaskType(ctx context.Context, id string, params *TaskTypeUpdateParams, opts ...RequestOption) (*CRMTaskType, *Response, error)
UpdateTaskType modifies a task type.
type CRMTask ¶
type CRMTask struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
ContactID *string `json:"contact_id,omitempty"`
DealID *string `json:"deal_id,omitempty"`
AssignedTo *string `json:"assigned_to,omitempty"`
AssignedTeamID *string `json:"assigned_team_id,omitempty"`
CreatedBy string `json:"created_by"`
Title string `json:"title"`
Description *string `json:"description,omitempty"`
DueDate *time.Time `json:"due_date,omitempty"`
// Priority is one of the TaskPriority* constants.
Priority string `json:"priority"`
// Type is a [CRMTaskType] name.
Type string `json:"type"`
// Status is one of the TaskStatus* constants.
Status string `json:"status"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
CRMTask is a unit of follow-up work, optionally attached to a contact or a deal and assigned to a member or a whole team.
type CRMTaskCreateParams ¶
type CRMTaskCreateParams struct {
ContactID *string `json:"contact_id,omitempty"`
DealID *string `json:"deal_id,omitempty"`
AssignedTo *string `json:"assigned_to,omitempty"`
AssignedTeamID *string `json:"assigned_team_id,omitempty"`
Title string `json:"title"`
Description *string `json:"description,omitempty"`
DueDate *time.Time `json:"due_date,omitempty"`
Priority string `json:"priority,omitempty"`
Type string `json:"type,omitempty"`
}
CRMTaskCreateParams creates a task. Title is required.
type CRMTaskListParams ¶ added in v0.3.0
type CRMTaskListParams struct {
ListOptions
// ContactID and DealID narrow to the tasks hanging off one record.
ContactID string
DealID string
// AssignedTo is an assignee user id.
AssignedTo string
// Status is one of the TaskStatus* constants.
Status string
}
CRMTaskListParams filters and paginates the plain task list. Every filter is optional and matches a single value; use TaskSearchParams with CRMService.SearchTasks when you need several values per facet, due-date bounds or an exact total.
type CRMTaskType ¶
type CRMTaskType struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Color string `json:"color"`
Position int `json:"position"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
CRMTaskType is a user-defined kind of work, for example Call or Meeting. Tasks reference their type by name, so deleting a type never orphans the tasks that used it; they keep the label and fall back to a neutral color.
type CRMTaskUpdateParams ¶
type CRMTaskUpdateParams struct {
AssignedTo *string `json:"assigned_to,omitempty"`
AssignedTeamID *string `json:"assigned_team_id,omitempty"`
Title *string `json:"title,omitempty"`
Description *string `json:"description,omitempty"`
DueDate *time.Time `json:"due_date,omitempty"`
Priority *string `json:"priority,omitempty"`
Type *string `json:"type,omitempty"`
Status *string `json:"status,omitempty"`
}
CRMTaskUpdateParams updates a task. Nil fields are left unchanged.
type Campaign ¶
type Campaign struct {
ID string `json:"id"`
UserID string `json:"user_id"`
OrganizationID *string `json:"organization_id,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
// Status is one of the CampaignStatus* constants.
Status string `json:"status"`
// Kind is [CampaignKindSequence] or [CampaignKindOneTime].
Kind string `json:"kind"`
// StopOnReply halts a contact's sequence as soon as they reply.
StopOnReply bool `json:"stop_on_reply"`
// OpenTracking enables open tracking via a tracking pixel.
OpenTracking bool `json:"open_tracking"`
// LinkTracking enables click tracking by rewriting links.
LinkTracking bool `json:"link_tracking"`
// TextOnly sends the plain-text body only, with no HTML part.
TextOnly bool `json:"text_only"`
// DailyLimit caps sends per mailbox per day for this campaign; each
// mailbox sends the smaller of this and its own cap.
DailyLimit int `json:"daily_limit"`
// UnsubscribeHeader adds RFC 8058 List-Unsubscribe headers.
UnsubscribeHeader bool `json:"unsubscribe_header"`
// RiskyEmails allows sending to addresses verification flagged as risky.
RiskyEmails bool `json:"risky_emails"`
// UnsubscribeMode picks the in-body opt-out appended after the signature:
// [UnsubscribeModeInherit] follows the organization setting in
// [OutreachSettings.Unsubscribe]; the other UnsubscribeMode* constants
// override it for this campaign.
UnsubscribeMode string `json:"unsubscribe_mode"`
// CC and BCC are copied on every send.
CC []string `json:"cc"`
BCC []string `json:"bcc"`
// StartDate and EndDate bound the active sending window. Both are nullable:
// a nil StartDate means "start now" and a nil EndDate means open-ended.
StartDate *time.Time `json:"start_date"`
EndDate *time.Time `json:"end_date"`
// Timezone is the IANA timezone the schedule is interpreted in.
Timezone string `json:"timezone"`
// Days is a legacy weekday bitmask (bit 0 is Monday), superseded by
// ScheduleWindows.
Days uint8 `json:"days"`
// StartTime and EndTime are legacy "HH:MM" bounds, superseded by
// ScheduleWindows.
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
// ScheduleWindows is the authoritative per-day schedule when non-empty.
ScheduleWindows ScheduleWindows `json:"schedule_windows"`
// EmailTags holds the mailbox tag ids the sending pool is drawn from under
// [SenderStrategyTags]. Folders holds the campaign's folder ids.
EmailTags []string `json:"email_tags"`
Folders []string `json:"folders"`
// ContactOrderBy, ContactOrderDir and ContactOrderField control the order
// contacts are enrolled in.
ContactOrderBy string `json:"contact_order_by"`
ContactOrderDir string `json:"contact_order_dir"`
ContactOrderField *string `json:"contact_order_field,omitempty"`
// SenderStrategy is [SenderStrategyTags] or [SenderStrategyExplicit];
// RotationMode picks how volume spreads across the chosen mailboxes.
SenderStrategy string `json:"sender_strategy"`
RotationMode string `json:"rotation_mode"`
// Senders is the explicit pool. It is loaded on demand rather than on every
// read; use [CampaignService.Senders] to fetch it.
Senders []CampaignSender `json:"senders,omitempty"`
// RampEnabled gradually increases daily volume for the campaign. The ramp
// only ever lowers volume: it is applied as a minimum against each
// mailbox's own cap. RampLevel is server-managed and survives pause/resume.
RampEnabled bool `json:"ramp_enabled"`
RampStart int `json:"ramp_start"`
RampIncrement int `json:"ramp_increment"`
RampCeiling int `json:"ramp_ceiling"`
RampLevel int `json:"ramp_level"`
RampLevelDate *time.Time `json:"ramp_level_date,omitempty"`
// ESPMatchMode is [ESPMatchOff], [ESPMatchPrefer] or [ESPMatchStrict].
ESPMatchMode string `json:"esp_match_mode"`
// MaxNewLeadsPerDay throttles newly enrolled contacts; 0 means unlimited.
MaxNewLeadsPerDay int `json:"max_new_leads_per_day"`
PrioritizeNewLeads bool `json:"prioritize_new_leads"`
// Continuous keeps the campaign active when it runs out of leads: instead
// of completing it waits, with IdleSince set, and sends the sequence to
// each lead as they arrive (from a linked segment, a form, the API or an
// automation). Anything that feeds it leads turns it on: linking a segment
// or a form, an automation that enrolls into it, or starting a campaign
// whose every lead has finished. A continuous campaign can be started with
// no leads at all; only its end date finishes it.
Continuous bool `json:"continuous"`
// IdleSince is set while a continuous campaign is waiting for leads and
// cleared as soon as it has something to send again.
IdleSince *time.Time `json:"idle_since,omitempty"`
// Auto-pause guardrails. Rates are percentages (0-100) evaluated over a
// rolling GuardrailWindowDays window every 15 minutes, and the campaign is
// moved to [CampaignStatusPausedGuardrail] the moment a band is breached.
// A rate of 0 disables that rule; GuardrailMinSample is the number of sends
// in the window below which no rule fires. GuardrailWindowDays 0 measures
// the campaign's whole history.
//
// Bounce and complaint rates are ceilings (pause at or above); the reply
// rate is a floor (pause below). Off by default.
GuardrailEnabled bool `json:"guardrail_enabled"`
GuardrailBounceRateMax float64 `json:"guardrail_bounce_rate_max"`
GuardrailComplaintRateMax float64 `json:"guardrail_complaint_rate_max"`
GuardrailReplyRateMin float64 `json:"guardrail_reply_rate_min"`
GuardrailMinSample int `json:"guardrail_min_sample"`
GuardrailWindowDays int `json:"guardrail_window_days"`
// GuardrailTrippedAt and GuardrailReason are server-owned: set when a
// guardrail pauses the campaign and cleared when it is started again.
GuardrailTrippedAt *time.Time `json:"guardrail_tripped_at,omitempty"`
GuardrailReason string `json:"guardrail_reason,omitempty"`
// TrackingDomain overrides the mailbox tracking domain for this campaign.
// It is honored only once verified.
TrackingDomain string `json:"tracking_domain"`
TrackingDomainVerified bool `json:"tracking_domain_verified"`
TrackingDomainVerifiedAt *time.Time `json:"tracking_domain_verified_at,omitempty"`
// UTMTracking tags every http(s) link in the body with utm_* parameters at
// send time; a link that already carries one keeps its own value. Empty
// UTMSource, UTMMedium and UTMCampaign mean the defaults ("warmbly",
// "email" and the campaign name as a slug); utm_content is always the
// link's own text. Off for campaigns created through the API unless sent.
UTMTracking bool `json:"utm_tracking"`
UTMSource string `json:"utm_source"`
UTMMedium string `json:"utm_medium"`
UTMCampaign string `json:"utm_campaign"`
LastStatusChangeAt *time.Time `json:"last_status_change_at,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
}
Campaign is an outreach campaign as returned by the API.
type CampaignAdvancedSettings ¶
type CampaignAdvancedSettings struct {
CampaignID string `json:"campaign_id"`
Overrides OutreachSettings `json:"overrides"`
UpdatedAt time.Time `json:"updated_at"`
}
CampaignAdvancedSettings is a campaign's override of the organization-wide outreach policy.
type CampaignAnalytics ¶
type CampaignAnalytics struct {
CampaignID string `json:"campaign_id"`
Name string `json:"name"`
Status string `json:"status"`
DateRange DateRange `json:"date_range"`
Summary CampaignAnalyticsTotals `json:"summary"`
Steps []StepAnalytics `json:"steps"`
DailyStats []DailyStat `json:"daily_stats,omitempty"`
// Engagement is the country, mail-client and device breakdown of human
// opens and clicks. It is best-effort: nil when the breakdown could not be
// computed, in which case Summary still stands on its own.
Engagement *CampaignEngagement `json:"engagement,omitempty"`
}
CampaignAnalytics is one campaign's engagement, broken down by step and, for human opens and clicks, by where and on what they happened.
type CampaignAnalyticsTotals ¶
type CampaignAnalyticsTotals struct {
TotalContacts int64 `json:"total_contacts"`
EmailsSent int64 `json:"emails_sent"`
// EmailsPending are queued sends not yet dispatched.
EmailsPending int64 `json:"emails_pending"`
UniqueOpens int64 `json:"unique_opens"`
// MachineOpens is the subset of UniqueOpens from automated fetchers
// (mail-privacy prefetch, UA-less clients). Human opens are
// UniqueOpens - MachineOpens.
MachineOpens int64 `json:"machine_opens"`
UniqueClicks int64 `json:"unique_clicks"`
// MachineClicks counts steps whose only clicks came from automated
// fetchers. They are not part of UniqueClicks, which only ever counts a
// person's click.
MachineClicks int64 `json:"machine_clicks"`
Replies int64 `json:"replies"`
Bounces int64 `json:"bounces"`
Unsubscribes int64 `json:"unsubscribes"`
OpenRate float64 `json:"open_rate"`
ClickRate float64 `json:"click_rate"`
ReplyRate float64 `json:"reply_rate"`
BounceRate float64 `json:"bounce_rate"`
}
CampaignAnalyticsTotals are a campaign's headline counters.
type CampaignAttachment ¶
type CampaignAttachment struct {
ID string `json:"id"`
CampaignID string `json:"campaign_id"`
// StepID is the step the file is sent with; nil means it rides every step
// of the campaign. The field is always present.
StepID *string `json:"step_id"`
Filename string `json:"filename"`
Size int64 `json:"size"`
MimeType string `json:"mime_type"`
// URL is a presigned download link, valid for about 15 minutes after the
// response; fetch the attachment again for a fresh one.
URL string `json:"url"`
CreatedAt time.Time `json:"created_at"`
}
CampaignAttachment is a file attached to a campaign, optionally scoped to a single step.
type CampaignComparison ¶
type CampaignComparison struct {
Campaigns []CampaignSummary `json:"campaigns"`
Period DateRange `json:"period"`
}
CampaignComparison compares several campaigns over one window.
type CampaignCreateParams ¶
type CampaignCreateParams struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
// Kind is [CampaignKindSequence] (the default) or [CampaignKindOneTime].
// It is fixed at creation. A one-time email accepts at most one entry in
// Steps.
Kind *string `json:"kind,omitempty"`
StopOnReply *bool `json:"stop_on_reply,omitempty"`
OpenTracking *bool `json:"open_tracking,omitempty"`
LinkTracking *bool `json:"link_tracking,omitempty"`
TextOnly *bool `json:"text_only,omitempty"`
DailyLimit *int `json:"daily_limit,omitempty"`
UnsubscribeHeader *bool `json:"unsubscribe_header,omitempty"`
RiskyEmails *bool `json:"risky_emails,omitempty"`
// UnsubscribeMode is one of the UnsubscribeMode* constants; the default
// is [UnsubscribeModeInherit].
UnsubscribeMode *string `json:"unsubscribe_mode,omitempty"`
CC []string `json:"cc,omitempty"`
BCC []string `json:"bcc,omitempty"`
StartDate *time.Time `json:"start_date,omitempty"`
EndDate *time.Time `json:"end_date,omitempty"`
Timezone *string `json:"timezone,omitempty"`
Days *uint8 `json:"days,omitempty"`
StartTime *string `json:"start_time,omitempty"`
EndTime *string `json:"end_time,omitempty"`
ScheduleWindows *ScheduleWindows `json:"schedule_windows,omitempty"`
// EmailTagIDs and FolderIDs reference tags and folders that already exist.
EmailTagIDs []string `json:"email_tag_ids,omitempty"`
FolderIDs []string `json:"folder_ids,omitempty"`
SenderStrategy *string `json:"sender_strategy,omitempty"`
RotationMode *string `json:"rotation_mode,omitempty"`
Senders []CampaignSenderInput `json:"senders,omitempty"`
RampEnabled *bool `json:"ramp_enabled,omitempty"`
RampStart *int `json:"ramp_start,omitempty"`
RampIncrement *int `json:"ramp_increment,omitempty"`
RampCeiling *int `json:"ramp_ceiling,omitempty"`
ESPMatchMode *string `json:"esp_match_mode,omitempty"`
MaxNewLeadsPerDay *int `json:"max_new_leads_per_day,omitempty"`
PrioritizeNewLeads *bool `json:"prioritize_new_leads,omitempty"`
// Continuous keeps the campaign active and waiting when it runs out of
// leads; see [Campaign.Continuous].
Continuous *bool `json:"continuous,omitempty"`
TrackingDomain *string `json:"tracking_domain,omitempty"`
// UTMTracking is off unless sent; empty UTMSource, UTMMedium and
// UTMCampaign keep the defaults. See [Campaign.UTMTracking].
UTMTracking *bool `json:"utm_tracking,omitempty"`
UTMSource *string `json:"utm_source,omitempty"`
UTMMedium *string `json:"utm_medium,omitempty"`
UTMCampaign *string `json:"utm_campaign,omitempty"`
// Steps seeds the sequence in order, each connected to the previous one
// with its wait set. Steps can equally be added afterwards with
// [CampaignService.CreateStep].
Steps []StepInput `json:"steps,omitempty"`
// Variants seeds A/B variants for the first step.
Variants []ABVariantCreateParams `json:"variants,omitempty"`
// AdvancedOverrides seeds this campaign's outreach-policy overrides.
AdvancedOverrides *OutreachSettings `json:"advanced_overrides,omitempty"`
}
CampaignCreateParams creates a campaign. Only Name is required; every other field falls back to a server default. The wizard sends everything at once, while a simple create can send just a name and description.
Segments are linked after creation with CampaignService.SetSegments, and auto-pause guardrails are configured with CampaignService.Update.
type CampaignDuplicateParams ¶ added in v0.3.0
type CampaignDuplicateParams struct {
// Name is the copy's name, 3 to 50 characters. Empty defaults to the source
// name with " (copy)" appended.
Name string `json:"name,omitempty"`
}
CampaignDuplicateParams is the optional body of CampaignService.Duplicate.
type CampaignEngagement ¶ added in v0.3.0
type CampaignEngagement struct {
// Countries is keyed by ISO 3166-1 alpha-2 country code.
Countries []EngagementBucket `json:"countries"`
// Clients is keyed by mail client or browser name.
Clients []EngagementBucket `json:"clients"`
// Devices is keyed by device type, for example "desktop" or "mobile".
Devices []EngagementBucket `json:"devices"`
}
CampaignEngagement is the "where from, on what" view of a campaign's human opens and clicks. Each list is ordered by activity and capped at the busiest buckets; an empty key means unknown.
type CampaignEstimateParams ¶ added in v0.3.0
type CampaignEstimateParams struct {
// SegmentIDs make up the audience (at most 20). A contact in several of
// them is counted once.
SegmentIDs []string `json:"segment_ids"`
// EmailTagIDs resolve the mailbox pool. Empty means every active mailbox
// in the organization.
EmailTagIDs []string `json:"email_tag_ids,omitempty"`
// DailyLimit is the per-mailbox campaign cap to apply (default 50). Each
// mailbox counts the smaller of this and its own cap.
DailyLimit *int `json:"daily_limit,omitempty"`
// Days is the weekday bitmask of sending days, bit 0 being Monday.
// Defaults to weekdays.
Days *uint8 `json:"days,omitempty"`
// Timezone is the IANA timezone the days are counted in. Defaults to UTC.
Timezone *string `json:"timezone,omitempty"`
// StartDate is when sending begins. Omit for now.
StartDate *time.Time `json:"start_date,omitempty"`
}
CampaignEstimateParams projects an audience against a sender pool before a campaign exists. Only SegmentIDs is required. Nothing is written.
type CampaignEstimateResult ¶ added in v0.3.0
type CampaignEstimateResult struct {
Recipients int `json:"recipients"`
Mailboxes int `json:"mailboxes"`
// DailyCapacity is the pool's per-day ceiling under the campaign limit;
// RemainingToday subtracts what the mailboxes already sent today.
DailyCapacity int `json:"daily_capacity"`
RemainingToday int `json:"remaining_today"`
// SendingDays is how many sending days the audience needs and
// EstimatedFinishAt the calendar day the last send lands on. Both are nil
// when the audience is empty, the pool has no capacity, or the send would
// take longer than two years.
SendingDays *int `json:"sending_days"`
EstimatedFinishAt *time.Time `json:"estimated_finish_at"`
}
CampaignEstimateResult is the projection from CampaignService.Estimate. It applies the scheduler's cap rule but none of its pacing, so it is the earliest the last send can land, not a promise.
type CampaignFolderCount ¶
CampaignFolderCount is one folder's campaign total.
type CampaignFormStats ¶ added in v0.3.0
type CampaignFormStats struct {
FormID string `json:"form_id"`
FormName string `json:"form_name"`
// PublicID is the form's public slug.
PublicID string `json:"public_id"`
// Status is the form's publication status.
Status string `json:"status"`
LinksSent int64 `json:"links_sent"`
Viewers int64 `json:"viewers"`
Starters int64 `json:"starters"`
Submissions int64 `json:"submissions"`
ShareURL string `json:"share_url,omitempty"`
}
CampaignFormStats is one form the campaign's emails link to, with what the campaign's recipients did with it. LinksSent counts personalized links minted for recipients; Viewers, Starters and Submissions are distinct recipients who opened, began and completed it.
type CampaignLeadCounts ¶
type CampaignLeadCounts struct {
Total int `json:"total"`
// Queued is the pending bucket; Processing is the active bucket.
Queued int `json:"queued"`
Processing int `json:"processing"`
Completed int `json:"completed"`
Replied int `json:"replied"`
Bounced int `json:"bounced"`
Failed int `json:"failed"`
Unsubscribed int `json:"unsubscribed"`
// Undeliverable leads were refused by address verification.
Undeliverable int `json:"undeliverable"`
// Engagement totals matching the LeadEngagement* filters: leads sent at
// least one step, and of those the ones with a human open, a click, or a
// reply on any step (whatever their derived status).
Contacted int `json:"contacted"`
Opened int `json:"opened"`
Clicked int `json:"clicked"`
RepliedAny int `json:"replied_any"`
}
CampaignLeadCounts are per-status lead totals within a single campaign, returned on the first page of a search that filters by exactly one campaign. They ignore the search's own lead-status and engagement filters, so every bucket shows its real total.
type CampaignListParams ¶
type CampaignListParams struct {
ListOptions
// Query is a free-text filter on campaign name.
Query string
// Folder restricts the list to a single folder id.
Folder string
// Status is a bucket filter: [CampaignStatusDraft], [CampaignStatusActive],
// [CampaignStatusPaused] (matches every paused_* variant) or
// [CampaignStatusCompleted]. Any other value is a 400.
Status string
// Kind is [CampaignKindSequence] or [CampaignKindOneTime]. Any other value
// is a 400.
Kind string
}
CampaignListParams filters and paginates a list of campaigns.
type CampaignLogEntry ¶
type CampaignLogEntry struct {
ID string `json:"id"`
CampaignID string `json:"campaign_id"`
// EventType names what happened, for example "started", "created" (also
// written for a duplicate, with source_campaign_id in Metadata) or "idle"
// when a continuous campaign runs out of leads and waits.
EventType string `json:"event_type"`
Message string `json:"message"`
Metadata map[string]any `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
CampaignLogEntry is a single entry from a campaign's activity log.
type CampaignSegmentLink ¶ added in v0.3.0
type CampaignSegmentLink struct {
SegmentID string `json:"segment_id"`
Name string `json:"name"`
Color string `json:"color"`
Description string `json:"description"`
ContactCount int `json:"contact_count"`
LeadCount int `json:"lead_count"`
HeldOutCount int `json:"held_out_count"`
LinkedAt time.Time `json:"linked_at"`
}
CampaignSegmentLink is one segment linked to a campaign as a live audience source. The counts are evaluated when asked: ContactCount is how many contacts the segment matches now, LeadCount how many of them are leads of this campaign, and HeldOutCount how many are not leads because they were removed from the campaign by hand and are never re-added automatically.
type CampaignSegmentsResult ¶ added in v0.3.0
type CampaignSegmentsResult struct {
Segments []CampaignSegmentLink `json:"data"`
Added int `json:"added"`
}
CampaignSegmentsResult is the outcome of CampaignService.SetSegments: the resulting links plus how many leads the call enrolled. Added is 0 when every member was already a lead, the segments match no contacts yet, or the only members are held out; the per-link counts tell these apart.
type CampaignSender ¶
type CampaignSender struct {
EmailAccountID string `json:"email_account_id"`
Weight int `json:"weight"`
LastSentAt *time.Time `json:"last_sent_at,omitempty"`
Enabled bool `json:"enabled"`
}
CampaignSender is one mailbox in an explicit-strategy campaign's sender pool.
type CampaignSenderInput ¶
type CampaignSenderInput struct {
EmailAccountID string `json:"email_account_id"`
Weight *int `json:"weight,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
CampaignSenderInput adds or updates one mailbox in the sender pool.
type CampaignService ¶
type CampaignService service
CampaignService manages outreach campaigns: their schedule and sending policy, their sequence steps, their sender pool, linked segments, A/B variants, attachments and the preflight checks run before they go live.
A campaign is an ordered sequence of steps (emails, waits and actions) delivered to enrolled contacts from one or more connected mailboxes. Steps are addressed as a sub-resource under their campaign.
func (*CampaignService) ABAnalysis ¶
func (s *CampaignService) ABAnalysis(ctx context.Context, id string, opts ...RequestOption) (*ABAnalysis, *Response, error)
ABAnalysis compares the campaign's A/B arms and names a winner once the result is significant.
func (*CampaignService) AdvancedSettings ¶
func (s *CampaignService) AdvancedSettings(ctx context.Context, id string, opts ...RequestOption) (*CampaignAdvancedSettings, *Response, error)
AdvancedSettings returns the campaign's overrides of the organization outreach policy.
func (*CampaignService) Create ¶
func (s *CampaignService) Create(ctx context.Context, params *CampaignCreateParams, opts ...RequestOption) (*Campaign, *Response, error)
Create creates a new campaign. It starts as a draft and sends nothing until started.
func (*CampaignService) CreateABVariant ¶
func (s *CampaignService) CreateABVariant(ctx context.Context, id string, params *ABVariantCreateParams, opts ...RequestOption) (*ABVariant, *Response, error)
CreateABVariant adds an A/B variant to the campaign.
func (*CampaignService) CreateStep ¶
func (s *CampaignService) CreateStep(ctx context.Context, id string, opts ...RequestOption) (*Step, *Response, error)
CreateStep appends a blank step to the campaign's sequence. Fill it in with CampaignService.UpdateStep. New steps are not connected to anything: wire them in through the previous step's Conditions. A one-time campaign refuses a second email step.
func (*CampaignService) Delete ¶
func (s *CampaignService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete permanently removes a campaign with its steps, lead progress and activity. A running campaign can be deleted directly: its pending sends are canceled with it. Contacts and emails already sent stay.
func (*CampaignService) DeleteABVariant ¶
func (s *CampaignService) DeleteABVariant(ctx context.Context, id, variantID string, opts ...RequestOption) (*Response, error)
DeleteABVariant removes an A/B variant.
func (*CampaignService) DeleteAttachment ¶
func (s *CampaignService) DeleteAttachment(ctx context.Context, id, attachmentID string, opts ...RequestOption) (*Response, error)
DeleteAttachment removes an attachment from the campaign and from storage.
func (*CampaignService) DeleteStep ¶
func (s *CampaignService) DeleteStep(ctx context.Context, id, stepID string, opts ...RequestOption) (*Response, error)
DeleteStep removes a step from the campaign's sequence, along with the attachments scoped to it.
func (*CampaignService) Duplicate ¶ added in v0.3.0
func (s *CampaignService) Duplicate(ctx context.Context, id string, params *CampaignDuplicateParams, opts ...RequestOption) (*Campaign, *Response, error)
Duplicate creates a draft copy of a campaign's configuration: every setting, the steps with their branch graph and canvas positions, tags, folders, the explicit sender list, A/B variants, advanced settings and attachments. Leads, progress, statistics, the activity log, the ramp level, a guardrail trip and any start or end date already in the past are not copied. The copy is owned by the caller, counts against the daily new-campaign throttle, and answers 201. params may be nil.
func (*CampaignService) Estimate ¶ added in v0.3.0
func (s *CampaignService) Estimate(ctx context.Context, params *CampaignEstimateParams, opts ...RequestOption) (*CampaignEstimateResult, *Response, error)
Estimate projects an audience of segments against a sender pool before a campaign exists: how many contacts it resolves to, the pool's daily capacity and the day the last send is expected to land. It writes nothing, so it needs no idempotency key.
func (*CampaignService) Forms ¶ added in v0.3.0
func (s *CampaignService) Forms(ctx context.Context, id string, opts ...RequestOption) ([]CampaignFormStats, *Response, error)
Forms returns the forms the campaign's emails link to, with what the campaign's recipients did with each.
func (*CampaignService) Get ¶
func (s *CampaignService) Get(ctx context.Context, id string, opts ...RequestOption) (*Campaign, *Response, error)
Get retrieves a single campaign by ID.
func (*CampaignService) List ¶
func (s *CampaignService) List(ctx context.Context, params *CampaignListParams, opts ...RequestOption) (*Page[Campaign], error)
List returns a page of campaigns. The page total counts campaigns matching the Query, Folder and Status filters.
func (*CampaignService) ListABVariants ¶
func (s *CampaignService) ListABVariants(ctx context.Context, id string, opts ...RequestOption) ([]ABVariant, *Response, error)
ListABVariants returns the campaign's A/B variants.
func (*CampaignService) ListAttachments ¶
func (s *CampaignService) ListAttachments(ctx context.Context, id string, opts ...RequestOption) ([]CampaignAttachment, *Response, error)
ListAttachments returns the campaign's attachments, campaign-wide and per-step alike.
func (*CampaignService) ListSegments ¶ added in v0.3.0
func (s *CampaignService) ListSegments(ctx context.Context, id string, opts ...RequestOption) ([]CampaignSegmentLink, *Response, error)
ListSegments returns the segments linked to the campaign as live audience sources, with their current member and lead counts.
func (*CampaignService) ListSteps ¶
func (s *CampaignService) ListSteps(ctx context.Context, id string, opts ...RequestOption) ([]Step, *Response, error)
ListSteps returns the campaign's sequence steps in order.
func (*CampaignService) Logs ¶
func (s *CampaignService) Logs(ctx context.Context, id string, params *ListOptions, opts ...RequestOption) (*Page[CampaignLogEntry], error)
Logs returns a page of a campaign's activity log, newest first. Limit is capped at 100.
func (*CampaignService) Overview ¶
func (s *CampaignService) Overview(ctx context.Context, opts ...RequestOption) (*CampaignsOverview, *Response, error)
Overview returns status-bucket and per-folder campaign counts for the organization.
func (*CampaignService) Preflight ¶
func (s *CampaignService) Preflight(ctx context.Context, id string, opts ...RequestOption) (*PreflightResult, *Response, error)
Preflight runs the pre-launch checks for a campaign without starting it.
func (*CampaignService) PreviewTemplate ¶
func (s *CampaignService) PreviewTemplate(ctx context.Context, params *TemplatePreviewParams, opts ...RequestOption) (*TemplatePreviewResult, *Response, error)
PreviewTemplate renders campaign copy the way the send path would. It is not scoped to a campaign in the path (name one in the params to include its footer and attachments) and sends nothing.
func (*CampaignService) ReplaceSenders ¶
func (s *CampaignService) ReplaceSenders(ctx context.Context, id string, senders []CampaignSenderInput, opts ...RequestOption) ([]CampaignSender, *Response, error)
ReplaceSenders replaces the campaign's explicit sender pool wholesale.
func (*CampaignService) SendTestEmail ¶
func (s *CampaignService) SendTestEmail(ctx context.Context, id string, params *TestEmailParams, opts ...RequestOption) (*TestEmailResult, *Response, error)
SendTestEmail sends a rendered preview of a step to a single address.
func (*CampaignService) Senders ¶
func (s *CampaignService) Senders(ctx context.Context, id string, opts ...RequestOption) ([]CampaignSender, *Response, error)
Senders returns the campaign's explicit sender pool.
func (*CampaignService) SetSegments ¶ added in v0.3.0
func (s *CampaignService) SetSegments(ctx context.Context, id string, segmentIDs []string, opts ...RequestOption) (*CampaignSegmentsResult, *Response, error)
SetSegments atomically replaces the campaign's linked segments (up to 20) and turns Campaign.Continuous on. Every current member of a newly linked segment is enrolled as a lead immediately, and contacts who enter a linked segment later are enrolled automatically within about two minutes. Enrolment is additive: a contact who leaves a segment keeps their lead row, and unlinking a segment stops future enrolment without touching existing leads. An active campaign wakes to send to the new leads; a completed one restarts through the launch checks when a linked segment grows.
An empty segmentIDs detaches every segment (the SDK sends an explicit empty array, which the API requires). The links and the enrolment are written in one transaction, so retries are safe.
func (*CampaignService) Start ¶
func (s *CampaignService) Start(ctx context.Context, id string, opts ...RequestOption) (*CampaignStatusChange, *Response, error)
Start begins (or resumes) sending for a campaign. It works from draft, any paused status or completed; a campaign closed by a passed end date resumes once that date is extended or cleared. Status changes are rate-limited to one per minute per campaign.
A campaign with nothing left to send does not finish again. The start turns CampaignUpdateParams.Continuous on if it was off, leaves the campaign CampaignStatusActive with Campaign.IdleSince set, and answers CampaignStatusChange.WaitingForLeads; the switch is written to the campaign's activity log. Adding a lead by any path then wakes it.
The start can be refused with ErrCodeListBounceRisk, ErrCodeLeadsUndeliverable or ErrCodeNoLeads in Error.Code; see CampaignService.StartWithOptions to launch past the bounce-risk gate.
func (*CampaignService) StartWithOptions ¶ added in v0.3.0
func (s *CampaignService) StartWithOptions(ctx context.Context, id string, params *CampaignStartParams, opts ...RequestOption) (*CampaignStatusChange, *Response, error)
StartWithOptions is CampaignService.Start with a body; params may be nil, in which case no body is sent.
func (*CampaignService) Stop ¶
func (s *CampaignService) Stop(ctx context.Context, id string, opts ...RequestOption) (*CampaignStatusChange, *Response, error)
Stop pauses sending for a campaign. Leads keep their place and resume from it on the next start.
func (*CampaignService) Update ¶
func (s *CampaignService) Update(ctx context.Context, id string, params *CampaignUpdateParams, opts ...RequestOption) (*Campaign, *Response, error)
Update modifies a campaign's settings.
func (*CampaignService) UpdateABVariant ¶
func (s *CampaignService) UpdateABVariant(ctx context.Context, id, variantID string, params *ABVariantUpdateParams, opts ...RequestOption) (*ABVariant, *Response, error)
UpdateABVariant modifies an A/B variant.
func (*CampaignService) UpdateAdvancedSettings ¶
func (s *CampaignService) UpdateAdvancedSettings(ctx context.Context, id string, overrides *OutreachSettings, opts ...RequestOption) (*Response, error)
UpdateAdvancedSettings replaces the campaign's outreach-policy overrides. The API answers 204 with no body; read them back with CampaignService.AdvancedSettings.
func (*CampaignService) UpdateStep ¶
func (s *CampaignService) UpdateStep(ctx context.Context, id, stepID string, params *StepUpdateParams, opts ...RequestOption) (*Step, *Response, error)
UpdateStep modifies a step's content, delay, routing or kind.
func (*CampaignService) UpdateStepLayout ¶
func (s *CampaignService) UpdateStepLayout(ctx context.Context, id string, positions []StepPosition, opts ...RequestOption) (*Response, error)
UpdateStepLayout persists the canvas coordinates of a campaign's steps. It is cosmetic: it does not audit, does not bump the campaign's updated_at, and is last-write-wins, so retries are safe. At most 1000 positions per call.
func (*CampaignService) UploadAttachment ¶
func (s *CampaignService) UploadAttachment(ctx context.Context, id string, file *FileUpload, stepID string, opts ...RequestOption) (*CampaignAttachment, *Response, error)
UploadAttachment attaches a file to the campaign. With stepID it is sent only with that step (which must belong to the campaign); without, it rides every step. Files are capped at 15 MB, executable and script types are refused, and the upload counts against the organization's storage quota (a 4xx with code "storage_limit_reached" when it would pass it). Answers 201.
func (*CampaignService) VerifyTrackingDomain ¶
func (s *CampaignService) VerifyTrackingDomain(ctx context.Context, id string, opts ...RequestOption) (*TrackingDomainStatus, *Response, error)
VerifyTrackingDomain re-resolves the campaign's tracking-domain override.
type CampaignStartParams ¶ added in v0.3.0
type CampaignStartParams struct {
// AcknowledgeListRisk launches past the bounce-risk gate
// ([ErrCodeListBounceRisk]), for a list verified elsewhere.
AcknowledgeListRisk bool `json:"acknowledge_list_risk"`
}
CampaignStartParams qualifies a CampaignService.StartWithOptions request.
type CampaignStatusChange ¶ added in v0.3.0
type CampaignStatusChange struct {
Status string `json:"status"`
// WaitingForLeads is true when a start found nothing left to send: the
// campaign is [CampaignStatusActive] with [Campaign.IdleSince] set, waiting
// for leads rather than finishing. Starting a campaign whose every lead has
// completed the sequence turns [CampaignUpdateParams.Continuous] on to get
// there, so a second start never answers no_remaining_leads.
//
// It is always false on a stop.
WaitingForLeads bool `json:"waiting_for_leads"`
}
CampaignStatusChange confirms a start or stop. Status is "started" or "stopped"; fetch the campaign for its resulting state.
type CampaignSummary ¶
type CampaignSummary struct {
CampaignID string `json:"campaign_id"`
Name string `json:"name"`
Status string `json:"status"`
EmailsSent int64 `json:"emails_sent"`
OpenRate float64 `json:"open_rate"`
ClickRate float64 `json:"click_rate"`
ReplyRate float64 `json:"reply_rate"`
BounceRate float64 `json:"bounce_rate,omitempty"`
}
CampaignSummary is one campaign's headline engagement.
type CampaignUpdateParams ¶
type CampaignUpdateParams struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Status *string `json:"status,omitempty"`
StopOnReply *bool `json:"stop_on_reply,omitempty"`
OpenTracking *bool `json:"open_tracking,omitempty"`
LinkTracking *bool `json:"link_tracking,omitempty"`
TextOnly *bool `json:"text_only,omitempty"`
DailyLimit *int `json:"daily_limit,omitempty"`
UnsubscribeHeader *bool `json:"unsubscribe_header,omitempty"`
RiskyEmails *bool `json:"risky_emails,omitempty"`
// UnsubscribeMode is one of the UnsubscribeMode* constants.
UnsubscribeMode *string `json:"unsubscribe_mode,omitempty"`
CC []string `json:"cc,omitempty"`
BCC []string `json:"bcc,omitempty"`
// StartDate and EndDate set the sending window. To clear a stored date
// (start now / run open-ended) leave the pointer nil and set
// ClearStartDate or ClearEndDate, which sends an explicit null.
StartDate *time.Time `json:"start_date,omitempty"`
EndDate *time.Time `json:"end_date,omitempty"`
// ClearStartDate and ClearEndDate null out the stored dates. They take
// precedence over StartDate and EndDate.
ClearStartDate bool `json:"-"`
ClearEndDate bool `json:"-"`
Timezone *string `json:"timezone,omitempty"`
Days *uint8 `json:"days,omitempty"`
StartTime *string `json:"start_time,omitempty"`
EndTime *string `json:"end_time,omitempty"`
ScheduleWindows *ScheduleWindows `json:"schedule_windows,omitempty"`
EmailTags []string `json:"email_tags,omitempty"`
Folders []string `json:"folders,omitempty"`
ContactOrderBy *string `json:"contact_order_by,omitempty"`
ContactOrderDir *string `json:"contact_order_dir,omitempty"`
ContactOrderField *string `json:"contact_order_field,omitempty"`
SenderStrategy *string `json:"sender_strategy,omitempty"`
RotationMode *string `json:"rotation_mode,omitempty"`
RampEnabled *bool `json:"ramp_enabled,omitempty"`
RampStart *int `json:"ramp_start,omitempty"`
RampIncrement *int `json:"ramp_increment,omitempty"`
RampCeiling *int `json:"ramp_ceiling,omitempty"`
ESPMatchMode *string `json:"esp_match_mode,omitempty"`
MaxNewLeadsPerDay *int `json:"max_new_leads_per_day,omitempty"`
PrioritizeNewLeads *bool `json:"prioritize_new_leads,omitempty"`
// Continuous keeps the campaign active and waiting when it runs out of
// leads; see [Campaign.Continuous]. Turning it off has the campaign finish
// once every lead is done.
Continuous *bool `json:"continuous,omitempty"`
TrackingDomain *string `json:"tracking_domain,omitempty"`
// UTM tagging; see [Campaign.UTMTracking].
UTMTracking *bool `json:"utm_tracking,omitempty"`
UTMSource *string `json:"utm_source,omitempty"`
UTMMedium *string `json:"utm_medium,omitempty"`
UTMCampaign *string `json:"utm_campaign,omitempty"`
// Auto-pause guardrails; see [Campaign.GuardrailEnabled]. Rates are
// percentages in [0,100] with 0 disabling the rule, GuardrailMinSample is
// 1-100000 and GuardrailWindowDays 0-365. The tripped-at marker and reason
// are server-owned and cleared by the next start.
GuardrailEnabled *bool `json:"guardrail_enabled,omitempty"`
GuardrailBounceRateMax *float64 `json:"guardrail_bounce_rate_max,omitempty"`
GuardrailComplaintRateMax *float64 `json:"guardrail_complaint_rate_max,omitempty"`
GuardrailReplyRateMin *float64 `json:"guardrail_reply_rate_min,omitempty"`
GuardrailMinSample *int `json:"guardrail_min_sample,omitempty"`
GuardrailWindowDays *int `json:"guardrail_window_days,omitempty"`
}
CampaignUpdateParams updates a campaign. Nil fields are left unchanged, so a zero value is never mistaken for "clear this".
Changing any schedule field (StartDate, EndDate, Timezone, Days, StartTime, EndTime, ScheduleWindows) on an active campaign reschedules its next send immediately. The explicit sender list is not editable here; use CampaignService.ReplaceSenders. Linked segments live under CampaignService.SetSegments.
func (CampaignUpdateParams) MarshalJSON ¶ added in v0.3.0
func (p CampaignUpdateParams) MarshalJSON() ([]byte, error)
MarshalJSON emits an explicit null for start_date/end_date when ClearStartDate/ClearEndDate is set, since the API distinguishes an absent field (unchanged) from a null one (cleared).
type CampaignUsage ¶
type CampaignUsage struct {
Total int `json:"total"`
Active int `json:"active"`
Paused int `json:"paused"`
Draft int `json:"draft"`
EmailsSent int64 `json:"emails_sent"`
}
CampaignUsage counts campaigns by state plus total volume.
type CampaignsOverview ¶
type CampaignsOverview struct {
Total int64 `json:"total"`
Active int64 `json:"active"`
Paused int64 `json:"paused"`
Draft int64 `json:"draft"`
Completed int64 `json:"completed"`
OneTime int64 `json:"one_time"`
Folders []CampaignFolderCount `json:"folders"`
}
CampaignsOverview backs the campaigns browser: status-bucket counts across the organization plus per-folder totals. Paused sums every paused_* variant; OneTime counts campaigns of CampaignKindOneTime whatever their status.
type CategoryPref ¶
type CategoryPref struct {
Enabled bool `json:"enabled"`
Channels ChannelPrefs `json:"channels"`
}
CategoryPref is one category's enable flag and channel toggles.
type ChangePlanParams ¶
type ChangePlanParams struct {
PlanID string `json:"plan_id"`
// ProrationBehavior controls how the provider settles the switch: one of
// the Proration* constants.
ProrationBehavior string `json:"proration_behavior,omitempty"`
DiscountCode string `json:"discount_code,omitempty"`
// Interval is [DurationMonth] or [DurationYear].
Interval string `json:"interval,omitempty"`
}
ChangePlanParams moves the workspace to a different plan.
type ChannelPrefs ¶
type ChannelPrefs struct {
InApp bool `json:"in_app"`
Email bool `json:"email"`
Slack bool `json:"slack"`
Push bool `json:"push"`
}
ChannelPrefs are the delivery toggles for one notification category.
type CheckoutParams ¶
type CheckoutParams struct {
// PriceID is the payment-provider price to buy.
PriceID string `json:"price_id"`
// SuccessURL and CancelURL are where the provider returns the user.
SuccessURL string `json:"success_url"`
CancelURL string `json:"cancel_url"`
// DiscountCode applies a promotion at checkout.
DiscountCode string `json:"discount_code,omitempty"`
}
CheckoutParams starts a plan checkout. PriceID, SuccessURL and CancelURL are required.
type CheckoutSession ¶
type CheckoutSession struct {
SessionID string `json:"session_id"`
CheckoutURL string `json:"checkout_url"`
}
CheckoutSession is a hosted checkout to send the user to.
type Client ¶
type Client struct {
// Emails manages connected mailboxes, their warmup and one-off sends.
Emails *EmailService
// Campaigns manages outreach campaigns, their steps and A/B variants.
Campaigns *CampaignService
// Contacts manages contacts, their CRM notes and import and export.
Contacts *ContactService
// Segments are saved contact audiences evaluated live.
Segments *SegmentService
// Suppressions is the workspace's do-not-contact list.
Suppressions *SuppressionService
// Forms are hosted lead-capture forms and their submissions.
Forms *FormService
// Unibox is the unified inbox: reading, replying and composing.
Unibox *UniboxService
// Templates manages reusable reply templates.
Templates *TemplateService
// Analytics reads aggregate analytics and deliverability health.
Analytics *AnalyticsService
// Advisor reads and acts on continuous checks of the sending posture.
Advisor *AdvisorService
// CRM manages pipelines, deals and the task board.
CRM *CRMService
// Teams groups members for CRM assignment.
Teams *TeamService
// Meetings lists calls booked through a connected scheduler.
Meetings *MeetingService
// Integrations manages third-party connections.
Integrations *IntegrationService
// Automations manages event-triggered flows across those connections.
Automations *AutomationService
// LeadSync manages Google Sheets to contacts sync.
LeadSync *LeadSyncService
// Generation writes and rewrites copy with AI.
Generation *GenerationService
// Skills manages the workspace AI playbooks that steer it.
Skills *SkillService
// Assistant drives the AI assistant and its connected MCP servers.
Assistant *AssistantService
// AgentTools is the AI tool registry over plain HTTP, for function-calling
// agents that do not speak MCP.
AgentTools *AgentToolService
// Webhooks manages webhook endpoints and their delivery log.
Webhooks *WebhookService
// APIKeys manages API keys.
APIKeys *APIKeyService
// OAuthApps registers and manages OAuth 2.1 applications.
OAuthApps *OAuthAppService
// Outreach reads and writes the organization-wide sending policy.
Outreach *OutreachService
// Deliverability ingests bounce and complaint events from upstream.
Deliverability *DeliverabilityService
// WarmupRouting manages warmup partner-selection rules.
WarmupRouting *WarmupRoutingService
// Tasks inspects and replays the send-task dead-letter queue.
Tasks *TaskService
// AuditLogs reads the organization audit trail.
AuditLogs *AuditLogService
// Folders group campaigns, Tags group mailboxes, and Categories group
// contacts and double as unified-inbox labels.
Folders *GroupService
Tags *GroupService
Categories *GroupService
// Meta reads the caller's identity, the plan catalog and the timezone list.
Meta *MetaService
// Auth signs a user in and manages the resulting session. Its routes, and
// those of Organization and Billing, are session-only: they need a token
// from [AuthService.Login] rather than an API key.
Auth *AuthService
// Organization manages the workspace, its members and its roles.
Organization *OrganizationService
// Billing manages the subscription, AI credits and referrals.
Billing *BillingService
// WebsiteTracking configures the website tracking snippet (session-only).
WebsiteTracking *WebsiteTrackingService
// PoolLink manages self-hosted instances linked to this workspace's warmup
// pool (session-only).
PoolLink *PoolLinkService
// CloudLink is a self-hosted instance's side of the warmup pool link
// (session-only).
CloudLink *CloudLinkService
// contains filtered or unexported fields
}
Client is a Warmbly API client. Create one with New. A Client is safe for concurrent use by multiple goroutines.
Resource groups are exposed as services hanging off the client, for example client.Campaigns and client.APIKeys.
func New ¶
New creates a Client. Exactly one credential option is required: WithAPIKey, WithAccessToken, WithTokenSource or WithAuthenticator.
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/warmbly/warmbly-go"
)
func main() {
client, err := warmbly.New(warmbly.WithAPIKey("wmbly_..."))
if err != nil {
log.Fatal(err)
}
page, err := client.Campaigns.List(context.Background(), nil)
if err != nil {
log.Fatal(err)
}
for _, c := range page.Data {
fmt.Println(c.Name, c.Status)
}
}
Output:
func (*Client) Do ¶
func (c *Client) Do(ctx context.Context, method, path string, body, out any, opts ...RequestOption) (*Response, error)
Do issues a request against an arbitrary API path, decoding a successful JSON body into out (which may be nil). It is the escape hatch for endpoints this SDK release does not model yet.
The path is resolved relative to the base URL, so pass it without the version prefix — "campaigns/123/steps", not "/v1/campaigns/123/steps". Retries, authentication, rate-limit parsing and typed errors work exactly as they do for the typed methods.
type ClientCredentialsConfig ¶
type ClientCredentialsConfig struct {
ClientID string
ClientSecret string
Scopes []string
// TokenURL overrides the token endpoint. Empty uses [DefaultEndpoint].
TokenURL string
// EndpointParams are extra parameters added to the token request.
EndpointParams url.Values
// HTTPClient is used for token requests. Nil uses a sensible default.
HTTPClient *http.Client
}
ClientCredentialsConfig configures the OAuth 2.1 client-credentials grant for machine-to-machine access (no user involved).
func (*ClientCredentialsConfig) NewClient ¶
NewClient builds a *Client authenticated with the client-credentials grant.
func (*ClientCredentialsConfig) Token ¶
func (c *ClientCredentialsConfig) Token(ctx context.Context) (*Token, error)
Token fetches a new access token using the client-credentials grant.
func (*ClientCredentialsConfig) TokenSource ¶
func (c *ClientCredentialsConfig) TokenSource(ctx context.Context) TokenSource
TokenSource returns a TokenSource that fetches and caches a token, renewing it as it expires. It is safe for concurrent use.
type CloudLinkConnectPollResult ¶ added in v0.3.0
type CloudLinkConnectPollResult struct {
// Status is [PoolLinkCodePending] or [PoolLinkCodeApproved]; a denied,
// expired or forgotten handshake is reported as an error.
Status string `json:"status"`
// Link is the stored connection, set once approved.
Link *CloudLinkConnection `json:"link,omitempty"`
// Info is the cloud's status document, set once approved when the cloud
// answered the follow-up call.
Info *PoolLinkInstanceInfo `json:"info,omitempty"`
}
CloudLinkConnectPollResult is one answer to CloudLinkService.PollConnect.
type CloudLinkConnection ¶ added in v0.3.0
type CloudLinkConnection struct {
// CloudURL is the Warmbly Cloud API the instance is linked to.
CloudURL string `json:"cloud_url"`
// InstanceID is the instance's ID on the cloud, as
// [PoolLinkInstance.ID] on the workspace's side.
InstanceID string `json:"instance_id"`
// OrganizationName is the cloud workspace's name at link time.
OrganizationName string `json:"organization_name"`
// ConnectedBy is the local member who ran the handshake.
ConnectedBy *string `json:"connected_by,omitempty"`
ConnectedAt time.Time `json:"connected_at"`
// LastSyncedAt is the last time the instance reached the cloud, and
// LastError the failure from the most recent attempt, if it failed.
LastSyncedAt *time.Time `json:"last_synced_at,omitempty"`
LastError string `json:"last_error,omitempty"`
}
CloudLinkConnection is the instance's link to a Warmbly Cloud workspace. The instance token is never serialized.
type CloudLinkMailbox ¶ added in v0.3.0
type CloudLinkMailbox struct {
// ID is the mailbox's ID on this instance, as [Email.ID].
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
// Provider is [ProviderGmail], [ProviderOutlook] or [ProviderSMTPIMAP].
Provider string `json:"provider"`
// Status is the local connection state, for example [MailboxStatusActive].
Status string `json:"status"`
// Enrolled reports whether the mailbox warms in the hosted pool; the
// instance's own warmup stands down for it while it does.
Enrolled bool `json:"enrolled"`
EnrolledAt *time.Time `json:"enrolled_at,omitempty"`
// Managed is true for a mailbox signed in through Warmbly Cloud: the
// credential lives on the cloud and the instance sends with brokered
// tokens.
Managed bool `json:"managed"`
// Cloud is the cloud's view of an enrolled mailbox (health, today's
// count, 7-day totals). Nil when not enrolled or when the cloud could not
// be reached for the listing.
Cloud *PoolLinkMailboxState `json:"cloud,omitempty"`
}
CloudLinkMailbox is one of the instance's active mailboxes with its pool enrollment, as listed on the Warmbly Cloud settings page.
type CloudLinkOAuthStart ¶ added in v0.3.0
type CloudLinkOAuthStart struct {
URL string `json:"url"`
// Session is single-use and expires after about 15 minutes.
Session string `json:"session"`
}
CloudLinkOAuthStart is the handle on a Google or Microsoft consent brokered by the cloud: open URL for the operator, then redeem Session with CloudLinkService.FinishOAuth once the window returns.
type CloudLinkPendingConnect ¶ added in v0.3.0
type CloudLinkPendingConnect struct {
// UserCode is the short code the operator types in on Warmbly Cloud.
UserCode string `json:"user_code"`
// VerificationURL is the cloud page that approves the code; it already
// carries the user code as a query parameter.
VerificationURL string `json:"verification_url"`
// CloudURL is the cloud the handshake was opened against.
CloudURL string `json:"cloud_url"`
// ExpiresAt is when an unapproved code is retired.
ExpiresAt time.Time `json:"expires_at"`
// Interval is the minimum number of seconds between polls.
Interval int `json:"interval"`
}
CloudLinkPendingConnect is an in-flight handshake: what to show the operator and how to poll. It lives in the instance's memory only, so a restart forgets it.
type CloudLinkService ¶ added in v0.3.0
type CloudLinkService service
CloudLinkService is a self-hosted instance's side of the warmup pool link, the "Settings > Warmbly Cloud" page: connect the instance to a Warmbly Cloud workspace, choose which local mailboxes warm in the hosted pool, and add Google or Microsoft mailboxes through Warmbly's own OAuth apps.
Only warmup moves to the cloud. Campaigns, contacts and the inbox stay on the instance. The link itself is a property of the instance, not of a workspace, so an instance holds at most one.
Connecting is a device-code handshake driven from here: CloudLinkService.Connect asks the cloud for a code and returns what to show the operator, who approves it on Warmbly Cloud; meanwhile CloudLinkService.WaitForConnect polls until the instance has its token.
Every route is session-only (a token from AuthService.Login, never an API key) and needs an active workspace on the session. Reads are open to any member, since no secret travels; connecting, polling and disconnecting are a settings change and need the manage-settings permission; enrolling, pausing, resuming, adopting and the OAuth sign-in are mailbox changes and need the manage-emails permission.
On a deployment without the cloud link (the hosted product itself, or an instance built without it) every route answers 501 Not Implemented.
func (*CloudLinkService) AdoptWorkspaceMailbox ¶ added in v0.3.0
func (s *CloudLinkService) AdoptWorkspaceMailbox(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
AdoptWorkspaceMailbox adds cloud workspace mailbox id (PoolLinkWorkspaceMailbox.ID) to the instance the same way as CloudLinkService.FinishOAuth: the cloud keeps the sign-in, the instance gets a credential-free mirror, returned here. A workspace mailbox can be linked to one instance at a time; a second adoption fails with "pool_link_already_adopted". Needs the manage-emails permission; recorded in the audit log.
func (*CloudLinkService) Connect ¶ added in v0.3.0
func (s *CloudLinkService) Connect(ctx context.Context, cloudURL string, opts ...RequestOption) (*CloudLinkPendingConnect, *Response, error)
Connect opens the handshake against cloudURL ("" for the instance's default, see CloudLinkStatus.DefaultCloudURL) and returns the code to show the operator. Follow up with CloudLinkService.WaitForConnect.
cloudURL must be https (loopback http is allowed for local development). An instance that is already linked fails with "cloud_link_connected": disconnect first. Needs the manage-settings permission.
func (*CloudLinkService) Disconnect ¶ added in v0.3.0
func (s *CloudLinkService) Disconnect(ctx context.Context, opts ...RequestOption) (*Response, error)
Disconnect ends the link. Every enrolled mailbox leaves the pool, their credentials are deleted on the cloud and local warmup takes over; mailboxes signed in through Warmbly Cloud are removed from the instance altogether, since they cannot send without the link (they stay in the cloud workspace). Needs the manage-settings permission; recorded in the audit log.
The cloud must confirm (or already have dropped) the link before local state goes, so a cloud outage fails the call rather than leaving managed mailboxes orphaned there; retry later.
func (*CloudLinkService) EnrollMailbox ¶ added in v0.3.0
func (s *CloudLinkService) EnrollMailbox(ctx context.Context, id string, opts ...RequestOption) (*CloudLinkMailbox, *Response, error)
EnrollMailbox sends mailbox id's SMTP/IMAP credential to the cloud and starts warming it in the hosted pool with the ramp settings it has on the instance; local warmup stands down for it. Idempotent for an enrolled mailbox. Needs the manage-emails permission; recorded in the audit log.
Only active SMTP/IMAP mailboxes qualify: one signed in with the instance's own Google or Microsoft OAuth app fails with "cloud_link_oauth_mailbox" (re-add it through CloudLinkService.StartOAuth instead), an inactive one with "cloud_link_mailbox_inactive", and one over the workspace's allowance with "pool_link_mailbox_limit".
func (*CloudLinkService) FinishOAuth ¶ added in v0.3.0
func (s *CloudLinkService) FinishOAuth(ctx context.Context, session string, opts ...RequestOption) (*Email, *Response, error)
FinishOAuth redeems a completed consent. The mailbox is created in the cloud workspace, where its sign-in lives, and starts warming in the pool at once; the instance gets a credential-free mirror of it, returned here, which campaigns and the inbox use through brokered access tokens. Needs the manage-emails permission; recorded in the audit log.
The session must belong to the session's workspace and is single-use; an unknown or expired one fails with "cloud_link_oauth_session", a consent the operator has not finished yet with "pool_link_oauth_pending".
func (*CloudLinkService) ListMailboxes ¶ added in v0.3.0
func (s *CloudLinkService) ListMailboxes(ctx context.Context, opts ...RequestOption) ([]CloudLinkMailbox, *Response, error)
ListMailboxes lists every active mailbox in the session's workspace with its pool enrollment and, for enrolled ones, the cloud's view. Open to any member. The listing makes one round trip to the cloud; when that fails the rows still come back, with CloudLinkMailbox.Cloud nil.
func (*CloudLinkService) ListWorkspaceMailboxes ¶ added in v0.3.0
func (s *CloudLinkService) ListWorkspaceMailboxes(ctx context.Context, opts ...RequestOption) ([]PoolLinkWorkspaceMailbox, *Response, error)
ListWorkspaceMailboxes lists the Google and Microsoft mailboxes connected directly on the linked cloud workspace that this instance may adopt. Open to any member; fails with "cloud_link_not_connected" without a link.
func (*CloudLinkService) PauseMailbox ¶ added in v0.3.0
func (s *CloudLinkService) PauseMailbox(ctx context.Context, id string, opts ...RequestOption) (*CloudLinkMailbox, *Response, error)
PauseMailbox pauses pool warmup for enrolled mailbox id without unenrolling it. Needs the manage-emails permission; recorded in the audit log. A mailbox that is not enrolled fails with not found.
func (*CloudLinkService) PollConnect ¶ added in v0.3.0
func (s *CloudLinkService) PollConnect(ctx context.Context, opts ...RequestOption) (*CloudLinkConnectPollResult, *Response, error)
PollConnect asks the cloud once whether the pending code has been approved, and on approval stores the instance token and returns the new link. Needs the manage-settings permission.
With no handshake in progress it fails with "cloud_link_no_pending" (or, if another session finished the handshake meanwhile, answers approved with the stored link); an expired code with "cloud_link_code_expired"; a code the member declined with "pool_link_denied". Wait at least CloudLinkPendingConnect.Interval seconds between calls.
func (*CloudLinkService) ResumeMailbox ¶ added in v0.3.0
func (s *CloudLinkService) ResumeMailbox(ctx context.Context, id string, opts ...RequestOption) (*CloudLinkMailbox, *Response, error)
ResumeMailbox resumes pool warmup for a paused mailbox. Needs the manage-emails permission; recorded in the audit log.
func (*CloudLinkService) StartOAuth ¶ added in v0.3.0
func (s *CloudLinkService) StartOAuth(ctx context.Context, provider string, opts ...RequestOption) (*CloudLinkOAuthStart, *Response, error)
StartOAuth begins a Google or Microsoft sign-in on Warmbly's own OAuth apps, so the instance needs no client of its own. provider is ProviderGmail or ProviderOutlook. Open the returned URL for the operator; the consent window returns to the instance's dashboard, which then calls CloudLinkService.FinishOAuth with the session. Needs the manage-emails permission and a live link.
func (*CloudLinkService) Status ¶ added in v0.3.0
func (s *CloudLinkService) Status(ctx context.Context, opts ...RequestOption) (*CloudLinkStatus, *Response, error)
Status reports whether the instance is linked, the cloud's view of it when reachable, and the default cloud URL. Open to any member.
func (*CloudLinkService) UnenrollMailbox ¶ added in v0.3.0
func (s *CloudLinkService) UnenrollMailbox(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
UnenrollMailbox takes mailbox id out of the pool. An SMTP/IMAP mailbox's credential is deleted on the cloud and local warmup takes over; a mailbox signed in through Warmbly Cloud is removed from the instance instead and stays in the cloud workspace. Succeeds for a mailbox that is not enrolled. Needs the manage-emails permission; recorded in the audit log.
func (*CloudLinkService) WaitForConnect ¶ added in v0.3.0
func (s *CloudLinkService) WaitForConnect(ctx context.Context, pending *CloudLinkPendingConnect, opts ...RequestOption) (*CloudLinkConnectPollResult, error)
WaitForConnect polls every CloudLinkPendingConnect.Interval seconds (never faster than once a second) until the operator approves the code, the instance reports a terminal error, or ctx is done. Once approved the link is stored on the instance and the result carries it.
The cloud retires an unapproved code at CloudLinkPendingConnect.ExpiresAt, after which the loop ends with a "cloud_link_code_expired" error; bound ctx yourself to give up sooner.
type CloudLinkStatus ¶ added in v0.3.0
type CloudLinkStatus struct {
// Connected reports whether the instance holds a link at all. Link is
// filled from the local row whenever it does.
Connected bool `json:"connected"`
Link *CloudLinkConnection `json:"link,omitempty"`
// Info is the cloud's own status document for this instance, including
// the pool allowance; it is set only when Reachable.
Info *PoolLinkInstanceInfo `json:"info,omitempty"`
// Reachable is false when the cloud could not be contacted just now;
// Error then carries the reason and Link still comes from the local row.
Reachable bool `json:"reachable"`
Error string `json:"error,omitempty"`
// DefaultCloudURL is the cloud [CloudLinkService.Connect] proposes when
// given no URL: WARMBLY_CLOUD_URL or the hosted API.
DefaultCloudURL string `json:"default_cloud_url"`
}
CloudLinkStatus is the dashboard's view of the link.
type ColdRamp ¶ added in v0.3.0
type ColdRamp struct {
// Ceiling is today's cold allowance; MailboxCap is what the owner
// configured.
Ceiling int `json:"ceiling"`
MailboxCap int `json:"mailbox_cap"`
// DaysToFullCap is how many clean days remain before Ceiling reaches
// MailboxCap, 0 when it arrives today.
DaysToFullCap int `json:"days_to_full_cap"`
// Held is true when a recent spam placement is pausing the climb.
Held bool `json:"held"`
}
ColdRamp explains a cold sending cap held below the mailbox's configured campaign limit while it graduates from warmup.
type ComposeCandidate ¶
type ComposeCandidate struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Provider string `json:"provider"`
// AuthState is the sending domain's SPF/DKIM/DMARC verdict.
AuthState string `json:"auth_state"`
WarmupActive bool `json:"warmup_active"`
DailyLimit int `json:"daily_limit"`
SentToday int `json:"sent_today"`
// RemainingToday is how much of the daily allowance is left.
RemainingToday int `json:"remaining_today"`
// HistoryMessages counts prior traffic between this mailbox and the
// recipient, which is the strongest affinity signal.
HistoryMessages int `json:"history_messages"`
LastContactAt *time.Time `json:"last_contact_at,omitempty"`
// Score ranks the candidate; Reasons explains the ranking in words.
Score int `json:"score"`
Reasons []string `json:"reasons"`
Recommended bool `json:"recommended"`
}
ComposeCandidate is one mailbox scored as a sender for a recipient.
type ComposeCandidates ¶
type ComposeCandidates struct {
Accounts []ComposeCandidate `json:"accounts"`
// RecommendedAccountID is what automatic selection would pick.
RecommendedAccountID *string `json:"recommended_account_id"`
RecommendedReason string `json:"recommended_reason"`
// Contact is the resolved contact for the address, when there is one.
Contact *Contact `json:"contact"`
// Suppression is non-nil when the address is suppressed workspace-wide, in
// which case a compose to it will be rejected.
Suppression *ComposeSuppression `json:"suppression"`
}
ComposeCandidates is the compose mailbox picker: every active mailbox scored against the recipient, the automatic recommendation and why, plus what is known about the address.
type ComposeDraft ¶
type ComposeDraft struct {
ID string `json:"id"`
EmailAccountID *string `json:"email_account_id,omitempty"`
To []string `json:"to"`
CC []string `json:"cc"`
BCC []string `json:"bcc"`
Subject string `json:"subject"`
Body string `json:"body"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
}
ComposeDraft is an autosaved compose draft. Ids are client-generated, which makes the upsert idempotent under debounced autosave.
type ComposeDraftParams ¶
type ComposeDraftParams struct {
// EmailAccountID is the chosen mailbox; empty or "auto" stores none.
EmailAccountID string `json:"email_account_id,omitempty"`
To []string `json:"to,omitempty"`
CC []string `json:"cc,omitempty"`
BCC []string `json:"bcc,omitempty"`
Subject string `json:"subject,omitempty"`
Body string `json:"body,omitempty"`
}
ComposeDraftParams is the body of an autosave. The server rejects a draft over 100,000 body bytes, 1,000 subject bytes or 100 recipients per field.
type ComposeResult ¶ added in v0.3.0
type ComposeResult struct {
SendResult
// AccountID and AccountEmail identify the sending mailbox.
AccountID string `json:"account_id"`
AccountEmail string `json:"account_email"`
// Auto is true when the server chose the mailbox, in which case
// PickedReason explains the choice in words.
Auto bool `json:"auto"`
PickedReason string `json:"picked_reason,omitempty"`
}
ComposeResult is returned when a composed message has been accepted for delivery. Beyond the queued send it reports which mailbox was used, which matters when the server picked it.
type ComposeSuppression ¶
type ComposeSuppression struct {
Reason string `json:"reason"`
}
ComposeSuppression explains why an address cannot be mailed.
type ConfirmParams ¶
type ConfirmParams struct {
// Session is the handle returned by the first step.
Session string `json:"session"`
Code string `json:"code"`
Turnstile string `json:"turnstile,omitempty"`
}
ConfirmParams completes a two-step flow with the emailed code.
type ConnectParams ¶
type ConnectParams struct {
// Provider is one of the Provider* constants.
Provider string `json:"provider"`
Label string `json:"label,omitempty"`
// Config carries the provider's credentials, which are sealed server-side.
Config map[string]any `json:"config,omitempty"`
}
ConnectParams connects a provider that authenticates with an API key or a webhook URL. Use IntegrationService.StartOAuth for OAuth providers.
type ConnectionConfigParams ¶
type ConnectionConfigParams struct {
ConfigCapabilities json.RawMessage `json:"config_capabilities,omitempty"`
// SyncDirection is [SyncPush], [SyncPull] or [SyncBoth].
SyncDirection string `json:"sync_direction,omitempty"`
}
ConnectionConfigParams updates a connection's non-secret configuration.
type ConnectionDetail ¶
type ConnectionDetail struct {
Connection *IntegrationConnection `json:"connection"`
Events []EventSubscription `json:"events"`
Runs []SyncRun `json:"runs"`
}
ConnectionDetail is a connection together with its event subscriptions and recent sync runs.
type ConnectionWebhookSecret ¶
type ConnectionWebhookSecret struct {
SigningSecret string `json:"signing_secret"`
SignatureHeader string `json:"signature_header"`
// Scheme names the signing algorithm the provider should use.
Scheme string `json:"scheme"`
}
ConnectionWebhookSecret is what an inbound provider needs to sign its callbacks to Warmbly.
type ConsentInfo ¶
type ConsentInfo struct {
ClientID string `json:"client_id"`
Name string `json:"name"`
Description string `json:"description"`
LogoURL string `json:"logo_url"`
WebsiteURL string `json:"website_url"`
RedirectURI string `json:"redirect_uri"`
// Scopes are the human-readable scope names being requested.
Scopes []string `json:"scopes"`
State string `json:"state"`
}
ConsentInfo is what a consent screen renders: who is asking, for what, and where the user will be sent back.
type Contact ¶
type Contact struct {
ID string `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Company string `json:"company"`
Phone string `json:"phone"`
CustomFields map[string]string `json:"custom_fields"`
// Subscribed is the marketing-consent flag. Campaigns never send to an
// unsubscribed contact.
Subscribed bool `json:"subscribed"`
Campaigns []MiniCampaign `json:"campaigns"`
Categories []MiniCategory `json:"categories"`
// VerificationStatus is the pre-send address check: [VerifyStatusValid],
// [VerifyStatusRisky], [VerifyStatusInvalid] or [VerifyStatusUnknown].
// Campaigns never send to invalid addresses, and send to risky ones only
// when their risky-emails setting is on.
VerificationStatus string `json:"verification_status"`
// VerificationReason is a short explanation of the verdict.
VerificationReason string `json:"verification_reason"`
// VerificationSubStatus refines the status: one of the
// VerificationSubStatus* constants, or empty.
VerificationSubStatus string `json:"verification_sub_status"`
// VerificationSource says who produced the verdict: one of the
// VerificationSource* constants, or empty when never checked.
VerificationSource string `json:"verification_source"`
// VerificationProvider names the verifier or vocabulary behind the
// verdict, for example [VerificationProviderBuiltin] or
// [VerificationProviderZeroBounce].
VerificationProvider string `json:"verification_provider"`
// VerificationConfidence is 0 to 100, scored from the last check plus what
// real mail to the address showed (deliveries, opens, replies, bounces).
VerificationConfidence int `json:"verification_confidence"`
IsCatchAll bool `json:"is_catch_all"`
VerificationCheckedAt *time.Time `json:"verification_checked_at,omitempty"`
// ESPProvider is the recipient's mail provider, derived from the domain:
// "", "gmail", "outlook" or "other". Campaign ESP matching keys off it.
ESPProvider string `json:"esp_provider"`
ESPResolvedAt *time.Time `json:"esp_resolved_at,omitempty"`
// CampaignLead is the contact's state within a single campaign. It is
// populated only when a search filters by exactly one campaign.
CampaignLead *ContactCampaignProgress `json:"campaign_lead,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
}
Contact is a contact (lead) as returned by the API.
type ContactActivity ¶
type ContactActivity struct {
ID string `json:"id"`
ContactID string `json:"contact_id"`
OrganizationID string `json:"organization_id"`
UserID *string `json:"user_id,omitempty"`
// ActivityType is one of the Activity* constants.
ActivityType string `json:"activity_type"`
Metadata map[string]any `json:"metadata"`
CreatedAt time.Time `json:"created_at"`
User *User `json:"user,omitempty"`
}
ContactActivity is one machine-recorded event on a contact's CRM record.
type ContactBulkUpdateParams ¶
type ContactBulkUpdateParams struct {
// Contacts are the contact ids to edit, at most 1,000 per request.
Contacts []string `json:"contacts"`
AddCampaigns []string `json:"add_campaigns,omitempty"`
RemoveCampaigns []string `json:"remove_campaigns,omitempty"`
AddCategories []string `json:"add_categories,omitempty"`
RemoveCategories []string `json:"remove_categories,omitempty"`
Fields []ContactFieldEdit `json:"fields,omitempty"`
// Subscribe sets the subscription flag on every listed contact.
Subscribe *bool `json:"subscribe,omitempty"`
}
ContactBulkUpdateParams edits many contacts at once.
type ContactCampaignProgress ¶
type ContactCampaignProgress struct {
// Status is one of the LeadStatus* constants.
Status string `json:"status"`
// Sent counts steps the worker delivered to the mailbox provider; a send
// that could not complete is retried later and never shows here.
Sent int `json:"sent"`
// Opened counts steps opened by a person. Automated fetches (mail privacy
// proxies and similar) are counted in MachineOpened instead.
Opened int `json:"opened"`
MachineOpened int `json:"machine_opened"`
Clicked int `json:"clicked"`
Replied int `json:"replied"`
Bounced int `json:"bounced"`
LastActivityAt *time.Time `json:"last_activity_at,omitempty"`
// CurrentStep labels the latest step actually sent. It is empty while the
// status is [LeadStatusPending].
CurrentStep string `json:"current_step,omitempty"`
// FailureReason is the sending worker's reason for the last failed send.
// Set only when Status is [LeadStatusFailed].
FailureReason string `json:"failure_reason,omitempty"`
}
ContactCampaignProgress is a contact's aggregate state inside one campaign.
type ContactCampaignState ¶ added in v0.3.0
type ContactCampaignState struct {
CampaignID string `json:"campaign_id"`
CampaignName string `json:"campaign_name"`
CampaignStatus string `json:"campaign_status"`
// LeadStatus is one of the LeadStatus* constants.
LeadStatus string `json:"lead_status"`
// FailureReason is the worker's reason for the last failed send.
FailureReason string `json:"failure_reason,omitempty"`
Steps []ContactCampaignStep `json:"steps"`
CompletedSteps int `json:"completed_steps"`
TotalSteps int `json:"total_steps"`
// CurrentStep is the latest step sent.
CurrentStep *ContactCampaignStep `json:"current_step,omitempty"`
LastAction string `json:"last_action,omitempty"`
LastActionAt *time.Time `json:"last_action_at,omitempty"`
// Next is nil once the flow has ended for the contact; EndedReason says
// why.
Next *ContactNextAction `json:"next,omitempty"`
EndedReason string `json:"ended_reason,omitempty"`
}
ContactCampaignState is one campaign a contact is a lead of: the flow with the contact's progress on each step, the derived lead status, the last thing that happened and what happens next.
type ContactCampaignStep ¶ added in v0.3.0
type ContactCampaignStep struct {
ID string `json:"id"`
Label string `json:"label"`
Kind string `json:"kind"`
Position int `json:"position"`
Subject string `json:"subject,omitempty"`
SentAt *time.Time `json:"sent_at,omitempty"`
OpenedAt *time.Time `json:"opened_at,omitempty"`
ClickedAt *time.Time `json:"clicked_at,omitempty"`
RepliedAt *time.Time `json:"replied_at,omitempty"`
BouncedAt *time.Time `json:"bounced_at,omitempty"`
FailedAt *time.Time `json:"failed_at,omitempty"`
// Attempts counts failed sends; InFlight means a worker holds a
// reservation whose result has not come back yet.
Attempts int `json:"attempts,omitempty"`
InFlight bool `json:"in_flight,omitempty"`
}
ContactCampaignStep is one flow node with the contact's progress on it.
type ContactCategoryCount ¶
type ContactCategoryCount struct {
CategoryID string `json:"category_id"`
Count int `json:"count"`
}
ContactCategoryCount is how many contacts carry one category.
type ContactCreatedPayload ¶ added in v0.3.0
type ContactCreatedPayload struct {
ContactID string `json:"contact_id"`
// ContactEmail is the address, named for the template variable rather than
// the column.
ContactEmail string `json:"contact_email"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Company string `json:"company,omitempty"`
Phone string `json:"phone,omitempty"`
// Subscribed is the marketing-consent flag. A new contact defaults to
// true unless the creating call said otherwise.
Subscribed bool `json:"subscribed"`
// CustomFields is the contact's custom column values, empty rather than
// null when it has none.
CustomFields map[string]string `json:"custom_fields,omitempty"`
// Source is the first-touch origin, one of the ContactSource* constants,
// and SourceDetail names the specific origin: the file name for an import,
// the API key's name for an API write, the form for a submission.
Source string `json:"source"`
SourceDetail string `json:"source_detail,omitempty"`
// CampaignIDs and CategoryIDs are the campaigns and lists the contact was
// created into, when it was created into any.
CampaignIDs []string `json:"campaign_ids,omitempty"`
CategoryIDs []string `json:"category_ids,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
ContactCreatedPayload is the EventContactCreated body: the contact's own fields plus where it came from, flat, so an automation template can read {{.contact_email}} without digging into a nested object.
It does not fire for every row that lands in the workspace. A write that matched an existing contact is an update, not a creation, and stays silent; so does a bulk arrival — a file import or a sheet sync — and so does any single write of more than 100 contacts, on the grounds that one upload should not flood an endpoint with thousands of deliveries. Reconcile bulk arrivals from the bulk_operation events or a list refetch instead.
type ContactDetail ¶
type ContactDetail struct {
Contact
Engagement ContactEngagement `json:"engagement"`
Suppression *ContactSuppression `json:"suppression,omitempty"`
// Verification explains the verdict: the reasons behind it and the
// observations it was scored from.
Verification *ContactVerificationDetail `json:"verification,omitempty"`
// Source is one of the ContactSource* constants; SourceDetail names the
// file, campaign, sheet, form, automation or API key behind it. Both are
// fixed at creation.
Source string `json:"source"`
SourceDetail string `json:"source_detail"`
FirstSeenAt time.Time `json:"first_seen_at"`
}
ContactDetail is the hydrated contact 360 view returned by ContactService.Get: the contact plus its engagement rollup, suppression state, verification explanation and first-touch attribution in one payload.
type ContactEngagement ¶
type ContactEngagement struct {
TotalSent int `json:"total_sent"`
TotalOpened int `json:"total_opened"`
TotalClicked int `json:"total_clicked"`
TotalReplied int `json:"total_replied"`
TotalBounced int `json:"total_bounced"`
TotalComplained int `json:"total_complained"`
LastSentAt *time.Time `json:"last_sent_at,omitempty"`
LastOpenedAt *time.Time `json:"last_opened_at,omitempty"`
LastClickedAt *time.Time `json:"last_clicked_at,omitempty"`
LastRepliedAt *time.Time `json:"last_replied_at,omitempty"`
LastBouncedAt *time.Time `json:"last_bounced_at,omitempty"`
}
ContactEngagement summarizes every email touchpoint recorded for a contact. Opens count people only: fetches by a mail client or security gateway are left out, as they are in campaign analytics. A person's click counts as an open too.
type ContactExportParams ¶
type ContactExportParams struct {
// Format is [ExportFormatCSV], [ExportFormatXLSX] or [ExportFormatJSON].
Format string `json:"format"`
// Scope is [ExportScopeAll], [ExportScopeFiltered] or [ExportScopeSelected].
Scope string `json:"scope"`
// ContactIDs is required for [ExportScopeSelected].
ContactIDs []string `json:"contact_ids,omitempty"`
// Filters is required for [ExportScopeFiltered]. With
// [ExportScopeSelected] it is optional and applied on top of ContactIDs;
// name the campaign there to populate the ExportFieldLead* columns.
Filters *ContactSearchParams `json:"filters,omitempty"`
// Fields are column identifiers in display order. Empty means the
// recommended default set.
Fields []string `json:"fields,omitempty"`
// Filename is the download name without an extension. Empty falls back to
// "contacts-<date>".
Filename string `json:"filename,omitempty"`
}
ContactExportParams describes an export. A single export is capped at 50,000 rows server-side.
type ContactFieldEdit ¶
type ContactFieldEdit struct {
// Type is one of the FieldOp* constants.
Type string `json:"type"`
Key string `json:"key"`
Value string `json:"value,omitempty"`
}
ContactFieldEdit is one custom-field change in a bulk update.
type ContactFieldFilter ¶
type ContactFieldFilter struct {
Name string `json:"name"`
Value string `json:"value"`
// Type is one of the Filter* constants.
Type string `json:"type"`
}
ContactFieldFilter matches one custom field.
type ContactImportParams ¶
type ContactImportParams struct {
Mapping []ImportColumnMapping `json:"mapping"`
// Dedup is one of the ImportDedup* constants.
Dedup string `json:"dedup,omitempty"`
HasHeader bool `json:"has_header"`
// CategoryIDs and CampaignIDs are applied to every imported contact.
CategoryIDs []string `json:"category_ids,omitempty"`
CampaignIDs []string `json:"campaign_ids,omitempty"`
// SegmentIDs pins every row into these segments as a manual include
// override: imported, updated and skipped-but-matched contacts alike.
SegmentIDs []string `json:"segment_ids,omitempty"`
// SubscribedDefault is what new contacts inherit when no subscribed column
// was mapped. It defaults to true server-side.
SubscribedDefault *bool `json:"subscribed_default,omitempty"`
}
ContactImportParams is the configuration committed alongside the file.
Exactly one column must map to ImportTargetEmail. A mapping with no email column, a custom column with no CustomKey, or a custom key with characters outside letters, numbers, underscores, spaces and dashes is a 400 on the whole request, raised before any row is written.
type ContactImportPreview ¶
type ContactImportPreview struct {
Filename string `json:"filename"`
Format string `json:"format"`
TotalRows int `json:"total_rows"`
// Columns are the detected headers. For a headerless file the server
// synthesizes "Column 1", "Column 2" and so on.
Columns []string `json:"columns"`
HasHeader bool `json:"has_header"`
// SampleRows are the first rows verbatim.
SampleRows [][]string `json:"sample_rows"`
// SuggestedMapping is a heuristic default the caller may override. It
// proposes [ImportTargetVerificationStatus] itself when a column's header
// or values look like another service's results.
SuggestedMapping []ImportColumnMapping `json:"suggested_mapping"`
}
ContactImportPreview describes an uploaded file before anything is written.
type ContactImportQuality ¶ added in v0.3.0
type ContactImportQuality struct {
// Malformed rows are not addresses at all; Disposable are on known
// throwaway domains.
Malformed int `json:"malformed"`
Disposable int `json:"disposable"`
// Role counts shared inboxes such as info@. Reported but not counted as
// bad, since mailing a shared inbox is a choice.
Role int `json:"role"`
BadSharePct float64 `json:"bad_share_pct"`
// Flagged is set above 25% on files of at least 20 rows, with a Summary
// sentence.
Flagged bool `json:"flagged"`
Summary string `json:"summary,omitempty"`
}
ContactImportQuality is what the uploaded addresses looked like, measured at import. It is advisory: a flagged import still stores every row it could parse. A list bad enough to matter is refused at campaign launch instead.
type ContactImportResult ¶
type ContactImportResult struct {
Total int `json:"total"`
Imported int `json:"imported"`
Updated int `json:"updated"`
Skipped int `json:"skipped"`
Failed int `json:"failed"`
StartedAt time.Time `json:"started_at"`
EndedAt time.Time `json:"ended_at"`
// Errors holds at most the first 1,000 per-row failures. Past that
// ErrorsTruncated is true and the counters, not the list, are the real
// totals.
Errors []ImportRowError `json:"errors,omitempty"`
ErrorsTruncated bool `json:"errors_truncated,omitempty"`
// Quality is the file's address-level assessment.
Quality *ContactImportQuality `json:"quality,omitempty"`
}
ContactImportResult summarizes a committed import. Every row lands in exactly one of Imported, Updated, Skipped or Failed, so those always sum to Total.
type ContactInput ¶
type ContactInput struct {
Email string `json:"email"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Company string `json:"company,omitempty"`
Phone string `json:"phone,omitempty"`
// Campaigns and Categories are ids to enroll the new contact in.
Campaigns []string `json:"campaigns,omitempty"`
Categories []string `json:"categories,omitempty"`
// Segments pins the contact into these segments as a manual include
// override, so it belongs whether or not the conditions match it. An
// unknown id is a 400 before any contact is written.
Segments []string `json:"segments,omitempty"`
// CustomFields keys may use letters, numbers, underscores, spaces and
// dashes.
CustomFields map[string]string `json:"custom_fields,omitempty"`
// Subscribed is the marketing-consent flag. Nil lets a new contact default
// to subscribed and an existing one keep what it had.
Subscribed *bool `json:"subscribed,omitempty"`
// VerificationStatus is a verdict you already hold for the address, in
// Warmbly's vocabulary (the VerifyStatus* constants) or any known
// service's ("ok", "catch-all", "do_not_mail", "deliverable", ...). It is
// stored as an imported verdict the background check leaves alone. A
// value no known service writes is rejected with code
// "unknown_verification_status".
VerificationStatus string `json:"verification_status,omitempty"`
// VerificationProvider names the vocabulary VerificationStatus is written
// in (a VerificationProvider* constant). Empty recognizes the value by
// itself; an unknown name is rejected with "unknown_verification_provider".
VerificationProvider string `json:"verification_provider,omitempty"`
// Source is the first-touch attribution stamped on a new contact. Only
// [ContactSourceManual] and [ContactSourceCampaign] may be claimed, and
// only by a user-scoped (OAuth) caller; a request authenticated with an
// API key is always recorded as [ContactSourceAPI] under the key's name.
// An existing contact keeps its original source.
Source string `json:"source,omitempty"`
}
ContactInput creates one contact. Email is required.
An address the organization already has is matched (case-insensitively) and enriched rather than duplicated: fields you send replace what is stored, fields you omit or leave empty are kept, and CustomFields is merged key by key. Use ContactService.Update to clear a value.
type ContactLinkClick ¶ added in v0.3.0
type ContactLinkClick struct {
ID string `json:"id"`
URL string `json:"url"`
Label string `json:"label,omitempty"`
UTMSource string `json:"utm_source,omitempty"`
UTMMedium string `json:"utm_medium,omitempty"`
UTMCampaign string `json:"utm_campaign,omitempty"`
UTMTerm string `json:"utm_term,omitempty"`
UTMContent string `json:"utm_content,omitempty"`
UserAgent string `json:"user_agent,omitempty"`
}
ContactLinkClick names the link behind an TimelineEmailClicked event: where it went, the anchor text it was minted from, and the UTM parameters the destination carried. Every link in an email is tracked on its own, so each link clicked is its own event. Clicks recorded before per-link attribution have no link.
type ContactNextAction ¶ added in v0.3.0
type ContactNextAction struct {
// StepID is nil while a branch condition is still undecided, in which
// case StepLabel says the step depends on the contact's response.
StepID *string `json:"step_id,omitempty"`
StepLabel string `json:"step_label"`
Kind string `json:"kind,omitempty"`
Subject string `json:"subject,omitempty"`
// State is one of the NextAction* constants.
State string `json:"state"`
// ScheduledAt is set only when due; NotBefore is the earliest the hard
// constraints allow; Constraint names the gate in user-facing words.
ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
NotBefore *time.Time `json:"not_before,omitempty"`
Constraint string `json:"constraint,omitempty"`
}
ContactNextAction is what happens next to a contact in a campaign. It is derived on read by the scheduler through the same constraints a real send goes through; nothing per contact is stored.
type ContactNote ¶
type ContactNote struct {
ID string `json:"id"`
ContactID string `json:"contact_id"`
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
Content string `json:"content"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// User is the note's author, joined in on read.
User *User `json:"user,omitempty"`
}
ContactNote is a free-text CRM note on a contact.
type ContactPage ¶
type ContactPage struct {
Page[Contact]
// Counts are organization-wide facet totals, present on the first page only.
Counts *ContactsCounts `json:"counts,omitempty"`
// LeadCounts are per-status totals for a single-campaign search, present on
// the first page only.
LeadCounts *CampaignLeadCounts `json:"lead_counts,omitempty"`
}
ContactPage is one page of contact search results. Beyond the page itself it carries the facet counts the API returns on the first page.
type ContactPageHit ¶ added in v0.3.0
type ContactPageHit struct {
ID string `json:"id"`
VisitorID string `json:"visitor_id"`
SessionKey string `json:"session_key"`
OccurredAt time.Time `json:"occurred_at"`
URL string `json:"url"`
Path string `json:"path"`
Title string `json:"title"`
Referrer string `json:"referrer"`
ReferrerDomain string `json:"referrer_domain"`
Landing bool `json:"landing"`
UTMSource string `json:"utm_source"`
UTMMedium string `json:"utm_medium"`
UTMCampaign string `json:"utm_campaign"`
UTMTerm string `json:"utm_term"`
UTMContent string `json:"utm_content"`
DeviceType string `json:"device_type"`
OS string `json:"os"`
Browser string `json:"browser"`
BrowserVersion string `json:"browser_version"`
DeviceBrand string `json:"device_brand"`
Language string `json:"language"`
Timezone string `json:"timezone"`
ScreenWidth int `json:"screen_width"`
ScreenHeight int `json:"screen_height"`
CountryCode string `json:"country_code"`
Region string `json:"region"`
City string `json:"city"`
}
ContactPageHit is one page view from the website tracking snippet, as carried by a TimelinePageHit event. Landing marks the first view of a session; the device, language, screen and location fields are empty or zero when unknown.
type ContactSearchParams ¶
type ContactSearchParams struct {
ListOptions
// Category is a convenience filter for a single category id.
Category string `json:"-"`
// Query is a free-text search across the core contact fields.
Query string `json:"query,omitempty"`
CustomFieldFilters []ContactFieldFilter `json:"custom_field_filters,omitempty"`
// CampaignIDs matches contacts enrolled in every listed campaign.
CampaignIDs []string `json:"campaign_ids,omitempty"`
// LeadStatus narrows to one derived lead status (a LeadStatus* constant)
// inside the single campaign in CampaignIDs. Any other number of campaigns
// is rejected with code "lead_filter_requires_campaign"; an unknown value
// with "invalid_lead_status".
LeadStatus string `json:"lead_status,omitempty"`
// Engagement narrows by engagement inside that same single campaign (a
// LeadEngagement* constant), ANDed with LeadStatus. It has the same
// single-campaign requirement; an unknown value is rejected with
// "invalid_engagement".
Engagement string `json:"engagement,omitempty"`
// CategoryIDs matches contacts carrying every listed category.
CategoryIDs []string `json:"category_ids,omitempty"`
// SegmentIDs matches contacts that are members of every listed segment
// (conditions plus manual overrides). A malformed id is a 400; an unknown
// segment matches nothing.
SegmentIDs []string `json:"segment_ids,omitempty"`
MinCampaigns *int `json:"min_campaigns,omitempty"`
MaxCampaigns *int `json:"max_campaigns,omitempty"`
Subscribed *bool `json:"subscribed,omitempty"`
// VerificationStatus filters by verdict: one of the VerifyStatus*
// constants.
VerificationStatus string `json:"verification_status,omitempty"`
CreatedAfter *time.Time `json:"created_after,omitempty"`
CreatedBefore *time.Time `json:"created_before,omitempty"`
UpdatedAfter *time.Time `json:"updated_after,omitempty"`
UpdatedBefore *time.Time `json:"updated_before,omitempty"`
// SortBy names the column to order by, for example "first_name" or
// "campaign_count".
SortBy string `json:"sort_by,omitempty"`
// Reverse switches the sort to descending.
Reverse bool `json:"reverse,omitempty"`
}
ContactSearchParams filters and paginates a contact search. Cursor, Limit and Category travel in the query string; every other field is sent in the body.
type ContactSegmentMembership ¶ added in v0.3.0
type ContactSegmentMembership struct {
ID string `json:"id"`
Name string `json:"name"`
Color string `json:"color"`
// Mode is "include" or "exclude" when the contact carries a manual
// override, and empty when the conditions alone decide.
Mode string `json:"mode,omitempty"`
// Member reports whether the contact is currently in the segment.
Member bool `json:"member"`
}
ContactSegmentMembership is one segment of the organization seen from a contact: whether the contact is in it right now and any manual override.
type ContactSentEmail ¶
type ContactSentEmail struct {
TaskID string `json:"task_id"`
Status string `json:"status"`
MessageID string `json:"message_id"`
Subject string `json:"subject"`
SentAt time.Time `json:"sent_at"`
EmailAccountID *string `json:"email_account_id,omitempty"`
EmailAccountEmail *string `json:"email_account_email,omitempty"`
EmailAccountName *string `json:"email_account_name,omitempty"`
CampaignID *string `json:"campaign_id,omitempty"`
CampaignName *string `json:"campaign_name,omitempty"`
StepID *string `json:"step_id,omitempty"`
StepName *string `json:"step_name,omitempty"`
OpenedAt *time.Time `json:"opened_at,omitempty"`
ClickedAt *time.Time `json:"clicked_at,omitempty"`
RepliedAt *time.Time `json:"replied_at,omitempty"`
BouncedAt *time.Time `json:"bounced_at,omitempty"`
}
ContactSentEmail is one row in the list of emails sent to a contact.
type ContactService ¶
type ContactService service
ContactService manages contacts (leads): search and bulk editing, the hydrated contact 360 view, address verification, per-campaign state, CRM notes and activities, import and export, and AI-assisted research.
func (*ContactService) Activities ¶
func (s *ContactService) Activities(ctx context.Context, id string, params *ListOptions, opts ...RequestOption) (*Page[ContactActivity], error)
Activities returns a page of the contact's recorded CRM activities.
func (*ContactService) AddNote ¶
func (s *ContactService) AddNote(ctx context.Context, id, content string, opts ...RequestOption) (*ContactNote, *Response, error)
AddNote appends a CRM note to the contact.
func (*ContactService) BatchResearch ¶
func (s *ContactService) BatchResearch(ctx context.Context, contactIDs []string, objective string, opts ...RequestOption) (int, *Response, error)
BatchResearch queues AI research for many contacts and returns how many runs were enqueued. They drain in the background; poll ContactService.ListResearch or subscribe to the gateway for progress.
func (*ContactService) BulkDelete ¶
func (s *ContactService) BulkDelete(ctx context.Context, ids []string, opts ...RequestOption) (*Response, error)
BulkDelete permanently removes the given contacts, at most 1,000 per request.
func (*ContactService) BulkUpdate ¶
func (s *ContactService) BulkUpdate(ctx context.Context, params *ContactBulkUpdateParams, opts ...RequestOption) ([]Contact, *Response, error)
BulkUpdate edits many contacts at once and returns the updated records. It takes at most 1,000 contacts per request and never creates contacts, so it never raises contact.created.
func (*ContactService) CampaignStates ¶ added in v0.3.0
func (s *ContactService) CampaignStates(ctx context.Context, id string, opts ...RequestOption) ([]ContactCampaignState, *Response, error)
CampaignStates returns, for every campaign the contact is a lead of, the flow with the contact's progress on each step, the derived lead status, and the scheduler's next action.
func (*ContactService) Create ¶
func (s *ContactService) Create(ctx context.Context, contacts []ContactInput, opts ...RequestOption) ([]Contact, *Response, error)
Create adds contacts to the organization and returns the resulting records, index-aligned with the input. An address that already exists is enriched rather than duplicated (see ContactInput). New addresses are queued for verification right away.
A contact.created webhook (and any automation it triggers) fires for each genuinely new row, but only when the request carries 100 contacts or fewer: a larger batch is treated as a bulk arrival, like a file import, and stays silent so one call cannot flood the organization's automations.
func (*ContactService) CustomFields ¶
func (s *ContactService) CustomFields(ctx context.Context, opts ...RequestOption) ([]string, *Response, error)
CustomFields returns the organization's distinct contact custom-field keys, most common first, capped at 200. Use it to populate a merge-tag picker.
func (*ContactService) Deals ¶
func (s *ContactService) Deals(ctx context.Context, id string, opts ...RequestOption) ([]Deal, *Response, error)
Deals returns the CRM deals attached to the contact.
func (*ContactService) Delete ¶
func (s *ContactService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete permanently removes a contact.
func (*ContactService) DeleteNote ¶
func (s *ContactService) DeleteNote(ctx context.Context, id, noteID string, opts ...RequestOption) (*Response, error)
DeleteNote removes a CRM note.
func (*ContactService) Emails ¶
func (s *ContactService) Emails(ctx context.Context, id string, opts ...RequestOption) ([]ContactSentEmail, *Response, error)
Emails returns the emails sent to a contact.
func (*ContactService) Export ¶
func (s *ContactService) Export(ctx context.Context, params *ContactExportParams, w io.Writer, opts ...RequestOption) (*Response, error)
Export streams the organization's contacts to w in the requested format. The response's X-Total-Rows header carries the row count.
func (*ContactService) Get ¶
func (s *ContactService) Get(ctx context.Context, id string, opts ...RequestOption) (*ContactDetail, *Response, error)
Get retrieves the hydrated contact 360 view.
func (*ContactService) ImportCommit ¶
func (s *ContactService) ImportCommit(ctx context.Context, file *FileUpload, params *ContactImportParams, opts ...RequestOption) (*ContactImportResult, *Response, error)
ImportCommit imports the file using the given mapping and options. Pass the same file that was used for ContactService.ImportPreview. Imports are capped at 50,000 rows, and new addresses are queued for verification right away.
An import is a bulk arrival: it never raises contact.created, however few rows it has, so one upload cannot flood the organization's automations and webhooks.
func (*ContactService) ImportPreview ¶
func (s *ContactService) ImportPreview(ctx context.Context, file *FileUpload, opts ...RequestOption) (*ContactImportPreview, *Response, error)
ImportPreview parses an uploaded CSV or XLSX and returns the detected columns and a suggested mapping, without writing anything.
func (*ContactService) ListResearch ¶
func (s *ContactService) ListResearch(ctx context.Context, id string, limit int, opts ...RequestOption) ([]ResearchRun, *Response, error)
ListResearch returns the contact's most recent research runs, newest first. A limit of 0 uses the server default of 20; the cap is 100.
func (*ContactService) ListTimeline ¶ added in v0.3.0
func (s *ContactService) ListTimeline(ctx context.Context, id string, params *TimelineParams, opts ...RequestOption) (*Page[TimelineEvent], error)
ListTimeline returns a page of the contact's merged activity feed: sends, opens, clicks (one per link), replies, bounces, deliverability and suppression events, notes, meetings, lifecycle events and page views. Pages resume at the exact position of the last event, so events sharing a timestamp are never skipped or repeated. Pagination.Total is always nil: the feed is merged from several tables and never counted.
func (*ContactService) Lookup ¶
func (s *ContactService) Lookup(ctx context.Context, email string, opts ...RequestOption) (*ContactDetail, *Response, error)
Lookup resolves an email address to a contact. A "Display Name <addr>" form is accepted and reduced to the bare address. The contact is nil when no contact in the organization owns that address.
func (*ContactService) Notes ¶
func (s *ContactService) Notes(ctx context.Context, id string, params *ListOptions, opts ...RequestOption) (*Page[ContactNote], error)
Notes returns a page of the contact's CRM notes.
func (*ContactService) RequestVerification ¶ added in v0.3.0
func (s *ContactService) RequestVerification(ctx context.Context, params *ContactVerificationParams, opts ...RequestOption) (*ContactVerificationResult, *Response, error)
RequestVerification queues a fresh check of the selected contacts or records a manual verdict on them, depending on ContactVerificationParams.Action. Verification runs in the background: poll the contacts or subscribe to the gateway to see verdicts land.
func (*ContactService) Research ¶
func (s *ContactService) Research(ctx context.Context, id, objective string, opts ...RequestOption) (*ResearchRun, *Response, error)
Research runs AI research against a single contact, in the request. It spends AI credits.
func (*ContactService) Search ¶
func (s *ContactService) Search(ctx context.Context, params *ContactSearchParams, opts ...RequestOption) (*ContactPage, error)
Search returns a page of contacts matching the filters.
func (*ContactService) Segments ¶ added in v0.3.0
func (s *ContactService) Segments(ctx context.Context, id string, opts ...RequestOption) ([]ContactSegmentMembership, *Response, error)
Segments returns every segment in the organization with whether the contact is currently a member and any manual override on it. Membership is evaluated live, so the answer reflects the contact as it is now.
func (*ContactService) Timeline ¶
func (s *ContactService) Timeline(ctx context.Context, id string, opts ...RequestOption) ([]TimelineEvent, *Response, error)
Timeline returns the first page of the contact's merged activity feed, newest first, using the server default of 50 events. Use ContactService.ListTimeline to page through the whole feed.
func (*ContactService) Update ¶
func (s *ContactService) Update(ctx context.Context, id string, params *ContactUpdateParams, opts ...RequestOption) (*Contact, *Response, error)
Update modifies a single contact.
func (*ContactService) UpdateNote ¶
func (s *ContactService) UpdateNote(ctx context.Context, id, noteID, content string, opts ...RequestOption) (*ContactNote, *Response, error)
UpdateNote rewrites a CRM note.
func (*ContactService) VerificationOverview ¶ added in v0.3.0
func (s *ContactService) VerificationOverview(ctx context.Context, opts ...RequestOption) (*ContactVerificationOverview, *Response, error)
VerificationOverview reports which verifier checks the workspace's addresses, its remaining credits, and the contacts by verdict.
type ContactSuppression ¶
type ContactSuppression struct {
// ID is the suppression-list entry; DELETE /suppressions/:id lifts it.
ID string `json:"id"`
// Kind is "email" when the contact's own address is on the list, or
// "domain" when its whole domain is. Value is the matching entry.
Kind string `json:"kind"`
Value string `json:"value"`
Reason string `json:"reason"`
// Source is "bounce", "complaint", "unsubscribe", "manual" or "import".
Source string `json:"source"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
ContactSuppression records why a contact's address is suppressed. It is nil when the contact is deliverable.
type ContactUpdateParams ¶
type ContactUpdateParams struct {
FirstName *string `json:"first_name,omitempty"`
LastName *string `json:"last_name,omitempty"`
Company *string `json:"company,omitempty"`
Phone *string `json:"phone,omitempty"`
CustomFields map[string]string `json:"custom_fields,omitempty"`
Subscribed *bool `json:"subscribed,omitempty"`
Campaigns []string `json:"campaigns,omitempty"`
Categories []string `json:"categories,omitempty"`
AddCategories []string `json:"add_categories,omitempty"`
RemoveCategories []string `json:"remove_categories,omitempty"`
}
ContactUpdateParams updates a single contact. Nil fields are unchanged.
Categories replaces the contact's categories wholesale, while AddCategories and RemoveCategories adjust them incrementally. Use one form or the other.
type ContactUsage ¶
type ContactUsage struct {
Total int64 `json:"total"`
Subscribed int64 `json:"subscribed"`
AddedToday int64 `json:"added_today"`
}
ContactUsage counts contacts.
type ContactVerificationCounts ¶ added in v0.3.0
type ContactVerificationCounts struct {
Valid int `json:"valid"`
Risky int `json:"risky"`
Invalid int `json:"invalid"`
Unknown int `json:"unknown"`
Pending int `json:"pending"`
}
ContactVerificationCounts is how many of the organization's contacts carry each verification status. Pending is the subset of Unknown nobody has checked yet.
type ContactVerificationDetail ¶ added in v0.3.0
type ContactVerificationDetail struct {
// Status is one of the VerifyStatus* constants.
Status string `json:"status"`
Confidence int `json:"confidence"`
// Reasons are sentences, strongest first.
Reasons []string `json:"reasons"`
// Decisive is true when real mail, rather than a check, decided the status.
Decisive bool `json:"decisive"`
// Evidence lists the observations the score came from, newest first.
Evidence []ContactVerificationEvidence `json:"evidence"`
}
ContactVerificationDetail is the "why" behind a contact's verdict, returned on the contact 360 view.
type ContactVerificationEvidence ¶ added in v0.3.0
type ContactVerificationEvidence struct {
// Kind is one of the VerificationEvidence* constants.
Kind string `json:"kind"`
Detail string `json:"detail,omitempty"`
ObservedAt time.Time `json:"observed_at"`
}
ContactVerificationEvidence is one observed fact about the mailbox that fed the verification confidence.
type ContactVerificationOverview ¶ added in v0.3.0
type ContactVerificationOverview struct {
// Provider is the verifier in use: [VerificationProviderBuiltin] or
// [VerificationProviderMillionVerifier].
Provider string `json:"provider"`
// ConnectionID is the integration connection behind a paid provider.
ConnectionID *string `json:"connection_id,omitempty"`
// Credits is the paid provider's remaining balance, when it could be read.
Credits *int `json:"credits,omitempty"`
// ProviderError is set when a paid provider is connected but unusable (a
// rejected key, no credits); the built-in check is in use meanwhile.
ProviderError string `json:"provider_error,omitempty"`
// BuiltinReady says whether the built-in mailbox probe can reach mail
// servers from this instance. Off, it still checks syntax, MX and
// disposable domains.
BuiltinReady bool `json:"builtin_ready"`
Counts ContactVerificationCounts `json:"counts"`
}
ContactVerificationOverview says who checks the workspace's addresses and how its contacts split by verdict.
type ContactVerificationParams ¶ added in v0.3.0
type ContactVerificationParams struct {
// Action is one of the VerificationAction* constants. Anything else is
// rejected with code "invalid_action".
Action string `json:"action"`
// Contacts are contact ids, at most 1,000 per request
// ("too_many_contacts").
Contacts []string `json:"contacts,omitempty"`
// CampaignID selects every lead of the campaign that verification refused
// (the [LeadStatusUndeliverable] ones), instead of or as well as Contacts.
CampaignID string `json:"campaign_id,omitempty"`
}
ContactVerificationParams selects contacts for ContactService.RequestVerification. Contacts and CampaignID combine; at least one contact must be selected or the request is rejected with code "no_contacts".
type ContactVerificationResult ¶ added in v0.3.0
type ContactVerificationResult struct {
Affected int `json:"affected"`
Action string `json:"action"`
// Queued is true for [VerificationActionVerify]: the check runs in the
// background rather than in the request.
Queued bool `json:"queued"`
}
ContactVerificationResult reports how many contacts a verification action touched.
type ContactsCounts ¶
type ContactsCounts struct {
Total int `json:"total"`
Subscribed int `json:"subscribed"`
Unsubscribed int `json:"unsubscribed"`
InCampaign int `json:"in_campaign"`
NotContacted int `json:"not_contacted"`
Categories []ContactCategoryCount `json:"categories"`
Verification ContactVerificationCounts `json:"verification"`
}
ContactsCounts are organization-wide contact facet totals, returned on the first page of a search for the browse sidebar. They are independent of the search's own filters.
type CreditBalance ¶
type CreditBalance struct {
// Unlimited is true on a deployment with no billing provider: AI is not
// metered there, every numeric field is zero and Packs is empty. Check it
// before rendering a balance as "0 left".
Unlimited bool `json:"unlimited"`
// Balance is the total spendable amount across both pools.
Balance int `json:"balance"`
MonthlyBalance int `json:"monthly_balance"`
PurchasedBalance int `json:"purchased_balance"`
// MonthlyAllowance is what the plan grants each month.
MonthlyAllowance int `json:"monthly_allowance"`
TotalPurchased int `json:"total_purchased"`
// MonthlyResetAt is when the monthly pool refills; NextResetAt is the end
// of the billing period.
MonthlyResetAt *time.Time `json:"monthly_reset_at,omitempty"`
NextResetAt *time.Time `json:"next_reset_at,omitempty"`
// Packs are the top-up bundles available for purchase.
Packs []CreditPack `json:"packs,omitempty"`
}
CreditBalance is the workspace's AI credit position across both pools: the monthly allowance that resets, and purchased credits that do not.
type CreditContext ¶
type CreditContext struct {
Detail string `json:"detail,omitempty"`
ThreadID string `json:"thread_id,omitempty"`
CampaignID string `json:"campaign_id,omitempty"`
ContactID string `json:"contact_id,omitempty"`
}
CreditContext names what a charge was actually for.
type CreditPack ¶
type CreditPack struct {
Key string `json:"key"`
Credits int `json:"credits"`
// PriceCents is the pack's price in the smallest currency unit.
PriceCents int `json:"price_cents,omitempty"`
Currency string `json:"currency,omitempty"`
Label string `json:"label,omitempty"`
}
CreditPack is a purchasable top-up bundle.
type CreditSettings ¶
type CreditSettings struct {
OrgID string `json:"org_id"`
// SpendLimit* cap workspace-wide spend per window. A nil value means no
// limit.
SpendLimitDaily *int `json:"spend_limit_daily"`
SpendLimitWeekly *int `json:"spend_limit_weekly"`
SpendLimitMonthly *int `json:"spend_limit_monthly"`
// MemberLimit* cap what one member can spend per window. Scheduled and
// system work is not counted against anyone.
MemberLimitDaily *int `json:"member_limit_daily"`
MemberLimitWeekly *int `json:"member_limit_weekly"`
MemberLimitMonthly *int `json:"member_limit_monthly"`
// LowBalanceThreshold is the balance at which an alert fires.
LowBalanceThreshold int `json:"low_balance_threshold"`
LowBalanceNotifiedAt *time.Time `json:"low_balance_notified_at,omitempty"`
// AutoTopup buys AutoTopupPack whenever the balance falls below
// AutoTopupThreshold, at most AutoTopupMaxPerMonth times a month.
AutoTopupEnabled bool `json:"auto_topup_enabled"`
AutoTopupPack string `json:"auto_topup_pack"`
AutoTopupThreshold int `json:"auto_topup_threshold"`
AutoTopupMaxPerMonth int `json:"auto_topup_max_per_month"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
CreditSettings are the workspace's AI spend controls.
type CreditSettingsParams ¶
type CreditSettingsParams struct {
SpendLimitDaily *int `json:"spend_limit_daily,omitempty"`
SpendLimitWeekly *int `json:"spend_limit_weekly,omitempty"`
SpendLimitMonthly *int `json:"spend_limit_monthly,omitempty"`
MemberLimitDaily *int `json:"member_limit_daily,omitempty"`
MemberLimitWeekly *int `json:"member_limit_weekly,omitempty"`
MemberLimitMonthly *int `json:"member_limit_monthly,omitempty"`
LowBalanceThreshold int `json:"low_balance_threshold,omitempty"`
AutoTopupEnabled bool `json:"auto_topup_enabled,omitempty"`
AutoTopupPack string `json:"auto_topup_pack,omitempty"`
AutoTopupThreshold int `json:"auto_topup_threshold,omitempty"`
AutoTopupMaxPerMonth int `json:"auto_topup_max_per_month,omitempty"`
}
CreditSettingsParams updates the spend controls. An omitted limit disables that limit.
type CreditTransaction ¶
type CreditTransaction struct {
ID string `json:"id"`
OrgID string `json:"org_id"`
Amount int `json:"amount"`
// Reason names the feature that spent, for example "reply_draft".
Reason string `json:"reason"`
ModelUsed string `json:"model_used,omitempty"`
TokensUsed int `json:"tokens_used"`
// BalanceAfter is the resulting total, captured atomically with the
// charge.
BalanceAfter int `json:"balance_after"`
// PurchasedDelta and PurchasedBalanceAfter track the purchased pool
// separately, so the log reconstructs both.
PurchasedDelta int `json:"purchased_delta"`
PurchasedBalanceAfter int `json:"purchased_balance_after"`
IdempotencyKey *string `json:"idempotency_key,omitempty"`
// ActorUserID is the member who triggered the charge; it is nil for
// scheduled or system work.
ActorUserID *string `json:"actor_user_id,omitempty"`
Context CreditContext `json:"context"`
CreatedAt time.Time `json:"created_at"`
}
CreditTransaction is one row of the append-only credit ledger. Amount is negative for spend and positive for grants and purchases.
type CreditUsage ¶
type CreditUsage struct {
SpentToday int `json:"spent_today"`
SpentWeek int `json:"spent_week"`
SpentMonth int `json:"spent_month"`
// LimitDaily, LimitWeekly and LimitMonthly are the configured spend caps.
// A nil value means no cap for that window.
LimitDaily *int `json:"limit_daily"`
LimitWeekly *int `json:"limit_weekly"`
LimitMonthly *int `json:"limit_monthly"`
Series []CreditUsagePoint `json:"series"`
ByReason []CreditUsageBucket `json:"by_reason"`
ByModel []CreditUsageBucket `json:"by_model"`
}
CreditUsage is AI spend over a window, with the daily series and breakdowns by feature and model.
type CreditUsageBucket ¶
type CreditUsageBucket struct {
Key string `json:"key"`
Credits int `json:"credits"`
Tokens int `json:"tokens"`
// Count is how many charges landed in this bucket.
Count int `json:"count"`
}
CreditUsageBucket is one slice of a usage breakdown.
type CreditUsagePoint ¶
type CreditUsagePoint struct {
// Date is a UTC calendar day formatted YYYY-MM-DD.
Date string `json:"date"`
Credits int `json:"credits"`
Tokens int `json:"tokens"`
}
CreditUsagePoint is one day of AI spend.
type DailyPlan ¶ added in v0.3.0
type DailyPlan struct {
EmailAccountID string `json:"email_account_id"`
// PlanDate is the local calendar date in Timezone, as YYYY-MM-DD.
PlanDate string `json:"plan_date"`
Timezone string `json:"timezone"`
// IsWorkingDay is false on a day the profile does not send at all.
IsWorkingDay bool `json:"is_working_day"`
// DailyLimit and HourlyLimit are the day's rolled cold-send target and
// hourly ceiling.
DailyLimit int `json:"daily_limit"`
HourlyLimit int `json:"hourly_limit"`
// WorkStartMinute and WorkEndMinute are the rolled workday as minutes
// since local midnight.
WorkStartMinute int `json:"work_start_minute"`
WorkEndMinute int `json:"work_end_minute"`
// LunchStartMinute and LunchEndMinute bound the rolled break; nil when
// the day carries none.
LunchStartMinute *int `json:"lunch_start_minute"`
LunchEndMinute *int `json:"lunch_end_minute"`
GapMinSeconds int `json:"gap_min_seconds"`
GapMaxSeconds int `json:"gap_max_seconds"`
CreatedAt time.Time `json:"created_at"`
// SentToday is completed cold sends from this mailbox on this local date.
SentToday int `json:"sent_today"`
// RemainingToday is what the plan still allows, floored at zero.
RemainingToday int `json:"remaining_today"`
// Behavior is the profile the plan was rolled from.
Behavior SendingBehavior `json:"behavior"`
}
DailyPlan is the workday a mailbox actually rolled for the current local date, plus how much of it is already spent. It is rolled once per local day and never updated, so every scheduling pass reads the same numbers. This is the read that answers "why is nothing sending right now".
type DailyStat ¶
type DailyStat struct {
// Date is a calendar day formatted YYYY-MM-DD.
Date string `json:"date"`
Sent int64 `json:"sent"`
Opens int64 `json:"opens"`
Clicks int64 `json:"clicks"`
Replies int64 `json:"replies"`
}
DailyStat is one day of engagement on a trend line.
type DangerZoneStatus ¶
type DangerZoneStatus struct {
// ResourceType is "organization" or "user".
ResourceType string `json:"resource_type"`
ResourceID string `json:"resource_id"`
ResourceName string `json:"resource_name"`
// ConfirmationHint is what the user must type to confirm: the workspace
// name, or their own email address.
ConfirmationHint string `json:"confirmation_hint"`
// GraceDays is how long the delete is delayed and remains cancelable.
GraceDays int `json:"grace_days"`
// PendingDeletion is set only while a delete is scheduled.
PendingDeletion *ScheduledDeletion `json:"pending_deletion,omitempty"`
}
DangerZoneStatus describes a workspace's or account's deletion state, plus the confirmation phrase a client should require before scheduling one.
type DashboardAnalytics ¶
type DashboardAnalytics struct {
// Period is [Period7Days], [Period30Days] or [Period90Days].
Period string `json:"period"`
OverallStats OverallStats `json:"overall_stats"`
RecentActivity []ActivityEvent `json:"recent_activity"`
TopCampaigns []CampaignSummary `json:"top_campaigns"`
AccountHealth AccountHealthTotals `json:"account_health"`
DailyTrend []DailyStat `json:"daily_trend"`
}
DashboardAnalytics is the organization-wide engagement summary.
type DeadLetter ¶
type DeadLetter struct {
ID string `json:"id"`
TaskID string `json:"task_id"`
// TaskType is what the task was doing, for example "campaign_email".
TaskType string `json:"task_type"`
// Payload is the original task body, kept so a replay is faithful.
Payload json.RawMessage `json:"payload,omitempty"`
LastError string `json:"last_error,omitempty"`
Attempts int `json:"attempts"`
MaxAttempts int `json:"max_attempts"`
// Status is the queue state, for example "pending" or "replayed".
Status string `json:"status"`
NextRetryAt *time.Time `json:"next_retry_at,omitempty"`
ReplayedAt *time.Time `json:"replayed_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
DeadLetter is one parked task.
type DeadLetterListParams ¶
type DeadLetterListParams struct {
// Status filters by queue state, for example "pending".
Status string
// Limit caps the rows returned, from 1 to 200. Zero uses the server
// default of 100.
Limit int
}
DeadLetterListParams filters the dead-letter queue.
type Deal ¶
type Deal struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
PipelineID string `json:"pipeline_id"`
StageID string `json:"stage_id"`
ContactID *string `json:"contact_id,omitempty"`
Name string `json:"name"`
// Value is the deal's amount in Currency.
Value *float64 `json:"value,omitempty"`
Currency string `json:"currency"`
// Status is [DealStatusOpen], [DealStatusWon] or [DealStatusLost].
Status string `json:"status"`
ExpectedCloseDate *time.Time `json:"expected_close_date,omitempty"`
WonAt *time.Time `json:"won_at,omitempty"`
LostAt *time.Time `json:"lost_at,omitempty"`
LostReason *string `json:"lost_reason,omitempty"`
AssignedTo *string `json:"assigned_to,omitempty"`
// CampaignID and SourceMailboxID attribute the deal to the outreach that
// produced it. They are a best guess and are editable.
CampaignID *string `json:"campaign_id,omitempty"`
SourceMailboxID *string `json:"source_mailbox_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// Contact, Stage and CampaignName are joined in by the list and search
// endpoints, not by single-deal reads.
Contact *Contact `json:"contact,omitempty"`
Stage *PipelineStage `json:"stage,omitempty"`
CampaignName *string `json:"campaign_name,omitempty"`
}
Deal is a sales opportunity moving through a pipeline.
type DealCreateParams ¶
type DealCreateParams struct {
PipelineID string `json:"pipeline_id"`
StageID string `json:"stage_id"`
ContactID *string `json:"contact_id,omitempty"`
Name string `json:"name"`
Value *float64 `json:"value,omitempty"`
Currency string `json:"currency,omitempty"`
ExpectedCloseDate *time.Time `json:"expected_close_date,omitempty"`
AssignedTo *string `json:"assigned_to,omitempty"`
CampaignID *string `json:"campaign_id,omitempty"`
SourceMailboxID *string `json:"source_mailbox_id,omitempty"`
}
DealCreateParams creates a deal. PipelineID, StageID and Name are required.
type DealListParams ¶ added in v0.3.0
type DealListParams struct {
ListOptions
// PipelineID and StageID narrow to one pipeline or one of its columns.
PipelineID string
StageID string
// Status is [DealStatusOpen], [DealStatusWon] or [DealStatusLost].
Status string
}
DealListParams filters and paginates the plain deal list. Every filter is optional and matches a single value; use DealSearchParams with CRMService.SearchDeals when you need several values per facet, a value range or an exact total.
type DealSearchParams ¶
type DealSearchParams struct {
ListOptions
// Query matches the deal name.
Query string `json:"query,omitempty"`
// Statuses matches any of [DealStatusOpen], [DealStatusWon] or
// [DealStatusLost].
Statuses []string `json:"statuses,omitempty"`
PipelineIDs []string `json:"pipeline_ids,omitempty"`
StageIDs []string `json:"stage_ids,omitempty"`
// AssignedTo matches any of the given owner user ids.
AssignedTo []string `json:"assigned_to,omitempty"`
CampaignIDs []string `json:"campaign_ids,omitempty"`
MinValue *float64 `json:"min_value,omitempty"`
MaxValue *float64 `json:"max_value,omitempty"`
CloseAfter *time.Time `json:"close_after,omitempty"`
CloseBefore *time.Time `json:"close_before,omitempty"`
CreatedAfter *time.Time `json:"created_after,omitempty"`
CreatedBefore *time.Time `json:"created_before,omitempty"`
// SortBy is "created_at", "updated_at", "value", "expected_close_date" or
// "name". Reverse switches to ascending; the default is descending.
SortBy string `json:"sort_by,omitempty"`
Reverse bool `json:"reverse,omitempty"`
}
DealSearchParams is the faceted filter shared by CRMService.SearchDeals and CRMService.DealsSummary. Every facet is optional; an empty body matches every deal in the organization. Slice facets match any of their values.
type DealStageSummary ¶
type DealStageSummary struct {
StageID string `json:"stage_id"`
Count int64 `json:"count"`
Value float64 `json:"value"`
}
DealStageSummary is one pipeline column's count and open value.
type DealUpdateParams ¶
type DealUpdateParams struct {
StageID *string `json:"stage_id,omitempty"`
ContactID *string `json:"contact_id,omitempty"`
Name *string `json:"name,omitempty"`
Value *float64 `json:"value,omitempty"`
Currency *string `json:"currency,omitempty"`
Status *string `json:"status,omitempty"`
ExpectedCloseDate *time.Time `json:"expected_close_date,omitempty"`
LostReason *string `json:"lost_reason,omitempty"`
AssignedTo *string `json:"assigned_to,omitempty"`
}
DealUpdateParams updates a deal. Nil fields are left unchanged. Setting Status to DealStatusWon or DealStatusLost closes it.
type DealsSummary ¶
type DealsSummary struct {
Total int64 `json:"total"`
OpenCount int64 `json:"open_count"`
OpenValue float64 `json:"open_value"`
WonCount int64 `json:"won_count"`
WonValue float64 `json:"won_value"`
LostCount int64 `json:"lost_count"`
LostValue float64 `json:"lost_value"`
Currency string `json:"currency"`
Stages []DealStageSummary `json:"stages"`
// MixedCurrency is true when the matching deals span several currencies,
// in which case the value sums are not directly comparable.
MixedCurrency bool `json:"mixed_currency"`
}
DealsSummary aggregates every deal matching a DealSearchParams, so a header total or a kanban column sum is exact rather than a page reduce.
type DeliverabilityBreakdown ¶
type DeliverabilityBreakdown struct {
EmailAccountID string `json:"email_account_id,omitempty"`
Email string `json:"email,omitempty"`
CampaignID string `json:"campaign_id,omitempty"`
Name string `json:"name,omitempty"`
Sent int64 `json:"sent"`
Bounces int64 `json:"bounces"`
Complaints int64 `json:"complaints"`
BounceRate float64 `json:"bounce_rate"`
ComplaintRate float64 `json:"complaint_rate"`
// Band is one of the Band* constants.
Band string `json:"band"`
}
DeliverabilityBreakdown is one mailbox's or campaign's contribution to deliverability. EmailAccountID and Email are set on the mailbox breakdown; CampaignID and Name on the campaign breakdown.
type DeliverabilityDashboard ¶
type DeliverabilityDashboard struct {
From time.Time `json:"from"`
To time.Time `json:"to"`
EventsTotal int64 `json:"events_total"`
BounceCount int64 `json:"bounce_count"`
ComplaintCount int64 `json:"complaint_count"`
UnsubscribeCount int64 `json:"unsubscribe_count"`
ReplyCount int64 `json:"reply_count"`
OpenCount int64 `json:"open_count"`
ClickCount int64 `json:"click_count"`
SuppressedRecipients int64 `json:"suppressed_recipients"`
// DLQPending is how many send tasks are parked in the dead-letter queue.
DLQPending int64 `json:"dlq_pending"`
IntentPositive int64 `json:"intent_positive"`
IntentNegative int64 `json:"intent_negative"`
IntentOutOfOffice int64 `json:"intent_out_of_office"`
IntentQuestion int64 `json:"intent_question"`
IntentNeutral int64 `json:"intent_neutral"`
EmailsSent int64 `json:"emails_sent"`
BounceRate float64 `json:"bounce_rate"`
ComplaintRate float64 `json:"complaint_rate"`
OpenRate float64 `json:"open_rate"`
ClickRate float64 `json:"click_rate"`
ReplyRate float64 `json:"reply_rate"`
// SpamPlacementRate and InboxPlacementRate come from seed-inbox testing;
// PlacementSamples is how many seeds backed them. Both rates are omitted
// (and decode as zero) when the window has no seed samples.
SpamPlacementRate float64 `json:"spam_placement_rate"`
InboxPlacementRate float64 `json:"inbox_placement_rate"`
PlacementSamples int64 `json:"placement_samples"`
// Band is the overall health verdict: one of the Band* constants. Score
// folds the same bounce, complaint and spam-placement rates into a 0 to
// 100 composite, higher being healthier.
Band string `json:"band"`
Score int `json:"score"`
Timeseries []DeliverabilityDay `json:"timeseries,omitempty"`
ByMailbox []DeliverabilityBreakdown `json:"by_mailbox,omitempty"`
ByCampaign []DeliverabilityBreakdown `json:"by_campaign,omitempty"`
// ByProvider breaks the seed placement results down per recipient
// provider.
ByProvider []ProviderPlacement `json:"by_provider,omitempty"`
// WarmupPlacement is the continuous warmup-derived placement signal per
// recipient domain.
WarmupPlacement []WarmupDomainPlacement `json:"warmup_placement,omitempty"`
}
DeliverabilityDashboard is the organization's sending health over a window: bounce and complaint pressure, inbox placement, reply intent, and the mailboxes and campaigns driving it.
type DeliverabilityDashboardSettings ¶
type DeliverabilityDashboardSettings struct {
Enabled bool `json:"enabled"`
ShowSuppressionLog bool `json:"show_suppression_log"`
ShowIntentSummary bool `json:"show_intent_summary"`
ShowDLQStats bool `json:"show_dlq_stats"`
}
DeliverabilityDashboardSettings toggles the panels on the deliverability view.
type DeliverabilityDay ¶
type DeliverabilityDay struct {
Date string `json:"date"`
Sent int64 `json:"sent"`
Bounces int64 `json:"bounces"`
Complaints int64 `json:"complaints"`
Opens int64 `json:"opens"`
Clicks int64 `json:"clicks"`
Replies int64 `json:"replies"`
Unsubscribes int64 `json:"unsubscribes"`
}
DeliverabilityDay is one day on the deliverability trend line.
type DeliverabilityEventParams ¶
type DeliverabilityEventParams struct {
// EventType is one of the DeliverabilityEvent* constants.
EventType string `json:"event_type"`
RecipientEmail string `json:"recipient_email"`
// CampaignID, TaskID and ContactID attribute the event when known.
CampaignID string `json:"campaign_id,omitempty"`
TaskID string `json:"task_id,omitempty"`
ContactID string `json:"contact_id,omitempty"`
// Provider names the upstream that reported the event, for example "ses".
Provider string `json:"provider,omitempty"`
Reason string `json:"reason,omitempty"`
// IdempotencyKey deduplicates the event body-side, independently of the
// Idempotency-Key header.
IdempotencyKey string `json:"idempotency_key,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
DeliverabilityEventParams describes a single deliverability event.
type DeliverabilityService ¶
type DeliverabilityService service
DeliverabilityService ingests deliverability events (bounces, complaints, deferrals) from an upstream mail pipeline, so a downstream processor such as an SES bounce handler can feed Warmbly's suppression list directly.
func (*DeliverabilityService) Ingest ¶
func (s *DeliverabilityService) Ingest(ctx context.Context, params *DeliverabilityEventParams, opts ...RequestOption) (*Response, error)
Ingest records a deliverability event for the organization. The API accepts the event asynchronously and answers 202 with no body.
type DiscountPreview ¶ added in v0.3.0
type DiscountPreview struct {
Valid bool `json:"valid"`
Reason string `json:"reason,omitempty"`
Code string `json:"code,omitempty"`
// Type is one of the DiscountType* constants; exactly one of PercentOff,
// AmountOff and TrialExtensionDays is set to match it.
Type string `json:"type,omitempty"`
PercentOff *int `json:"percent_off,omitempty"`
AmountOff *float64 `json:"amount_off,omitempty"`
Currency *string `json:"currency,omitempty"`
TrialExtensionDays *int `json:"trial_extension_days,omitempty"`
// Duration is one of the DiscountDuration* constants, with
// DurationInMonths set when it repeats.
Duration string `json:"duration,omitempty"`
DurationInMonths *int `json:"duration_in_months,omitempty"`
// OriginalAmount, DiscountedAmount and SavingsAmount are only computed
// when a plan was named and the code is a money discount.
OriginalAmount *float64 `json:"original_amount,omitempty"`
DiscountedAmount *float64 `json:"discounted_amount,omitempty"`
SavingsAmount *float64 `json:"savings_amount,omitempty"`
}
DiscountPreview is what a promotion code would do. Check Valid first: an unusable code answers 200 with Valid false and a Reason, rather than an error.
type DiscountRedemption ¶ added in v0.3.0
type DiscountRedemption struct {
ID string `json:"id"`
DiscountCodeID string `json:"discount_code_id"`
OrganizationID string `json:"organization_id"`
RedeemedBy *string `json:"redeemed_by,omitempty"`
SubscriptionID *string `json:"subscription_id,omitempty"`
PlanID *string `json:"plan_id,omitempty"`
StripeCouponID *string `json:"stripe_coupon_id,omitempty"`
StripeCheckoutSessionID *string `json:"stripe_checkout_session_id,omitempty"`
// Type is one of the DiscountType* constants.
Type string `json:"type"`
PercentOff *int `json:"percent_off,omitempty"`
AmountOff *float64 `json:"amount_off,omitempty"`
Currency *string `json:"currency,omitempty"`
TrialExtensionDays *int `json:"trial_extension_days,omitempty"`
// Status is one of the DiscountRedemption* constants.
Status string `json:"status"`
RedeemedAt time.Time `json:"redeemed_at"`
AppliedAt *time.Time `json:"applied_at,omitempty"`
// Code is the promotion's code, when the API joins it in.
Code string `json:"code,omitempty"`
}
DiscountRedemption is one promotion code the workspace has redeemed.
type DomainAuthCheck ¶
type DomainAuthCheck struct {
Domain string `json:"domain"`
SPFFound bool `json:"spf_found"`
SPFRecord string `json:"spf_record,omitempty"`
// DKIMFound is advisory: selectors are not discoverable from DNS, so a
// missing DKIM never fails the domain on its own.
DKIMFound bool `json:"dkim_found"`
DKIMSelectors []string `json:"dkim_selectors,omitempty"`
DMARCFound bool `json:"dmarc_found"`
// DMARCPolicy is the record's p= value, or its sp= value when the policy
// is inherited from the organizational domain.
DMARCPolicy string `json:"dmarc_policy,omitempty"`
// DMARCDomain is where the DMARC record was actually found. It differs
// from Domain when the policy is inherited.
DMARCDomain string `json:"dmarc_domain,omitempty"`
// DMARCInherited reports that the sending domain has no DMARC record of
// its own and is covered by its organizational domain's policy, which is
// how a dedicated sending subdomain normally works. SPF never inherits.
DMARCInherited bool `json:"dmarc_inherited"`
// Reserved marks a special-use domain (.test, .invalid, .localhost,
// .example, .local) that cannot resolve by definition. It is recorded as
// [AuthStateUnknown] rather than failing.
Reserved bool `json:"reserved"`
AllAligned bool `json:"all_aligned"`
// LookupError is true when an authoritative lookup failed transiently
// (timeout, SERVFAIL, network) rather than the record being absent. Treat
// the result as unknown, not as a misconfiguration.
LookupError bool `json:"lookup_error"`
Summary string `json:"summary"`
}
DomainAuthCheck is the live SPF/DKIM/DMARC lookup for a sending domain.
type DynamicClient ¶
type DynamicClient struct {
ClientID string `json:"client_id"`
// ClientSecret is set only for a confidential registration.
ClientSecret string `json:"client_secret,omitempty"`
// ClientIDIssuedAt is a Unix timestamp.
ClientIDIssuedAt int64 `json:"client_id_issued_at"`
ClientName string `json:"client_name,omitempty"`
RedirectURIs []string `json:"redirect_uris"`
GrantTypes []string `json:"grant_types"`
ResponseTypes []string `json:"response_types"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method"`
// Scope is what was actually granted, which is capped below what a
// human-registered application can hold: a self-registered client can
// never send mail or mint credentials.
Scope string `json:"scope"`
}
DynamicClient is the RFC 7591 client-information response.
type DynamicClientParams ¶
type DynamicClientParams struct {
ClientName string `json:"client_name,omitempty"`
RedirectURIs []string `json:"redirect_uris"`
// GrantTypes and ResponseTypes default to the authorization-code flow.
GrantTypes []string `json:"grant_types,omitempty"`
ResponseTypes []string `json:"response_types,omitempty"`
// TokenEndpointAuthMethod of "none" registers a public client, which
// authenticates with PKCE and holds no secret.
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
// Scope is the space-delimited set being asked for.
Scope string `json:"scope,omitempty"`
ClientURI string `json:"client_uri,omitempty"`
LogoURI string `json:"logo_uri,omitempty"`
}
DynamicClientParams self-registers a client at runtime, the RFC 7591 way that an MCP client uses to get credentials without a human registering an app first.
type EditParams ¶
type EditParams struct {
// Text is the passage to rewrite.
Text string `json:"text"`
// Instruction is what to change about it.
Instruction string `json:"instruction"`
// Context is the surrounding draft, which is fenced so quoted inbound mail
// inside it cannot steer the rewrite.
Context string `json:"context,omitempty"`
Tone string `json:"tone,omitempty"`
}
EditParams rewrites an existing passage.
type Email ¶
type Email struct {
ID string `json:"id"`
UserID string `json:"user_id"`
OrganizationID *string `json:"organization_id,omitempty"`
// WorkerID identifies the worker currently handling this mailbox, when assigned.
WorkerID *string `json:"worker_id"`
Email string `json:"email"`
Name string `json:"name"`
SignaturePlain string `json:"signature_plain"`
SignatureHTML string `json:"signature_html"`
// SignatureSync mirrors the signature configured at the provider instead of
// the one stored here.
SignatureSync bool `json:"signature_sync"`
// SignatureCode reports whether the HTML signature is edited as raw markup.
SignatureCode bool `json:"signature_code"`
// Provider is the mailbox backend: [ProviderGmail], [ProviderOutlook] or
// [ProviderSMTPIMAP].
Provider string `json:"provider"`
// Status is the connection state: [MailboxStatusActive],
// [MailboxStatusInactive] or [MailboxStatusRevoked].
Status string `json:"status"`
// LastSyncedAt is when the mailbox was last polled for inbound mail; nil
// until the first sync has run. [EmailService.SyncStatus] has the detail.
LastSyncedAt *time.Time `json:"last_synced_at"`
// LastID is the provider-side sync watermark.
LastID *int64 `json:"last_id"`
// CampaignLimit caps how many campaign messages a day this mailbox sends
// (0 to 5000; the default is 50). It is a ceiling only: the campaign's
// daily limit, the warmup ramp, sending behavior and the workspace's daily
// send limit all still apply and the smallest wins.
CampaignLimit int `json:"campaign_limit"`
// MinWaitTime is the minimum gap, in seconds, between two sends (default
// 600). Jitter is added on top. While sending behavior is enabled the
// behavior's gap range replaces it.
MinWaitTime int `json:"min_wait_time"`
// ReplyTo is the Reply-To address; empty uses the mailbox address.
ReplyTo string `json:"reply_to"`
// SaveToSent applies to SMTP/IMAP mailboxes only: after a send the worker
// files a copy in the mailbox's Sent folder, since SMTP submission puts
// nothing in the account by itself. Gmail and Outlook file their own copy
// and ignore the flag. Warmup mail is never filed.
SaveToSent bool `json:"save_to_sent"`
// TrackingDomain is the custom open/click tracking subdomain, or "" for
// the shared host. Only a verified domain is used at send time; see
// [EmailService.GetTrackingDomain].
TrackingDomain string `json:"tracking_domain"`
TrackingDomainVerified bool `json:"tracking_domain_verified"`
TrackingDomainVerifiedAt *time.Time `json:"tracking_domain_verified_at"`
// AuthState summarizes SPF/DKIM/DMARC for the sending domain, as refreshed
// by the background sweep: [AuthStatePassing], [AuthStateFailing] or
// [AuthStateUnknown]. A sustained failing state gates cold sending and
// warmup; see AuthFailingSince.
AuthState string `json:"auth_state"`
AuthSPF bool `json:"auth_spf"`
// AuthDKIM is advisory: DKIM selectors are not discoverable from DNS, so a
// missing DKIM never forces a failing verdict on its own.
AuthDKIM bool `json:"auth_dkim"`
AuthDMARC bool `json:"auth_dmarc"`
AuthDMARCPolicy string `json:"auth_dmarc_policy,omitempty"`
AuthReason string `json:"auth_reason,omitempty"`
AuthCheckedAt *time.Time `json:"auth_checked_at,omitempty"`
// AuthFailingSince is when the domain entered [AuthStateFailing], and nil
// otherwise. The grace period runs from here, so a resolver hiccup or a
// record broken minutes ago never stops sending immediately. Fix the DNS
// and call [EmailService.RefreshAuthCheck] to clear it right away.
AuthFailingSince *time.Time `json:"auth_failing_since,omitempty"`
// Warmup is the warmup ramp anchor; a nil value means warmup is disabled.
Warmup *time.Time `json:"warmup"`
// WarmupPausedAt is when warmup was paused, when it is currently paused.
WarmupPausedAt *time.Time `json:"warmup_paused_at"`
WarmupBase int `json:"warmup_base"`
WarmupMax int `json:"warmup_max"`
WarmupIncrease int `json:"warmup_increase"`
WarmupReplyRate int `json:"warmup_reply_rate"`
WarmupTag string `json:"warmup_tag"`
// WarmupPoolType is the partner pool this mailbox warms in: "free" or
// "premium".
WarmupPoolType string `json:"warmup_pool_type"`
// WarmupStartTime and WarmupEndTime bound the daily warmup window as
// "HH:MM" in the mailbox timezone.
WarmupStartTime string `json:"warmup_start_time"`
WarmupEndTime string `json:"warmup_end_time"`
// WarmupDays is a bitmask of the weekdays warmup runs on.
WarmupDays int `json:"warmup_days"`
// Timezone is the mailbox's own IANA zone, which its sending behavior and
// business-hours window are evaluated in. Empty means not configured, so
// only the campaign's own window applies.
Timezone string `json:"timezone"`
// Tags holds the ids of the tags applied to this mailbox.
Tags []string `json:"tags"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Email is a connected email account (mailbox) as returned by the API.
func (*Email) WarmupActive ¶
WarmupActive reports whether warmup is enabled and running.
func (*Email) WarmupEnabled ¶
WarmupEnabled reports whether warmup is enabled for this mailbox, whether or not it is currently paused.
func (*Email) WarmupPaused ¶
WarmupPaused reports whether warmup is enabled but paused. A paused mailbox keeps its ramp progress.
type EmailAccountUsage ¶
type EmailAccountUsage struct {
Total int `json:"total"`
Active int `json:"active"`
InWarmup int `json:"in_warmup"`
WithErrors int `json:"with_errors"`
}
EmailAccountUsage counts mailboxes by state.
type EmailListParams ¶
type EmailListParams struct {
ListOptions
// Query is a free-text search over the mailbox address and name.
Query string
// Tag filters to mailboxes carrying the given tag id. It must be a UUID;
// anything else is rejected with a 400.
Tag string
}
EmailListParams filters and paginates a list of connected mailboxes. The page size defaults to 50 when Limit is zero.
type EmailService ¶
type EmailService service
EmailService manages connected email accounts (mailboxes), their warmup configuration, their sending-domain authentication, their humanlike sending behavior and the one-off messages sent through them.
func (*EmailService) Allowance ¶ added in v0.3.0
func (s *EmailService) Allowance(ctx context.Context, opts ...RequestOption) (*MailboxAllowance, *Response, error)
Allowance reports how many mailboxes the workspace holds, how many it may hold and why, and any open request for more. Read it before a connect so a refusal is never a surprise after the credentials were typed: every connect path fails with a 403 carrying ErrCodeMailboxAllowanceReached once Remaining is zero. Requires an organization to be selected.
func (*EmailService) AppealWarmupBan ¶
func (s *EmailService) AppealWarmupBan(ctx context.Context, id string, params *WarmupAppealParams, opts ...RequestOption) (*WarmupAppealResult, *Response, error)
AppealWarmupBan submits an appeal against a mailbox's warmup ban.
func (*EmailService) AuthCheck ¶
func (s *EmailService) AuthCheck(ctx context.Context, id string, opts ...RequestOption) (*DomainAuthCheck, *Response, error)
AuthCheck runs a live SPF/DKIM/DMARC lookup against the mailbox's sending domain. It is read-only: it reports what DNS says right now and leaves the mailbox's stored Email.AuthState alone. Use EmailService.RefreshAuthCheck to record the verdict.
func (*EmailService) Behavior ¶ added in v0.3.0
func (s *EmailService) Behavior(ctx context.Context, id string, opts ...RequestOption) (*SendingBehavior, *Response, error)
Behavior returns the mailbox's sending-behavior profile, substituting the defaults for a mailbox that has never been configured so the result is always a complete profile. Deployments without the behavior engine answer with a 400.
func (*EmailService) BehaviorPlan ¶ added in v0.3.0
func (s *EmailService) BehaviorPlan(ctx context.Context, id string, opts ...RequestOption) (*DailyPlan, *Response, error)
BehaviorPlan returns the workday the mailbox rolled for the current local date and how much of it is already spent.
func (*EmailService) BulkTag ¶
func (s *EmailService) BulkTag(ctx context.Context, params *BulkTagParams, opts ...RequestOption) (*BulkTagResult, *Response, error)
BulkTag adds and removes tags across many mailboxes in one call.
func (*EmailService) ConnectSMTPIMAP ¶
func (s *EmailService) ConnectSMTPIMAP(ctx context.Context, params *SMTPIMAPParams, opts ...RequestOption) (*Email, *Response, error)
ConnectSMTPIMAP connects a mailbox by its own credentials. The server dials both legs to validate them before storing anything, so a bad password fails here rather than silently at send time. An address that is already connected is refused with a 409.
func (*EmailService) ConnectSMTPIMAPBulk ¶ added in v0.3.0
func (s *EmailService) ConnectSMTPIMAPBulk(ctx context.Context, params *SMTPIMAPBulkParams, opts ...RequestOption) (*MailboxBulkResult, *Response, error)
ConnectSMTPIMAPBulk connects up to MaxSMTPIMAPBulkRows SMTP/IMAP mailboxes in one call, answered per row so one bad row never hides the others: the call itself succeeds with a 200 even when every row failed, so read MailboxBulkResult.Summary and each row's Status. Rows past the workspace's allowance fail with ErrCodeMailboxAllowanceReached before any credential is dialed. Re-sending a batch is safe: an already connected mailbox is MailboxBulkSkipped, never doubled, so no idempotency key is needed. Every credential is validated against its own server, so a large batch takes a few seconds per mailbox.
func (*EmailService) Delete ¶
func (s *EmailService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete disconnects and removes a mailbox for good, together with its imported mail, warmup history, credentials and any send still scheduled for it. A campaign that was using it keeps running on its remaining senders. Set the mailbox inactive with EmailService.Update when you only want it to stop.
The worker syncing the mailbox is told to drop it before the record is removed. If that instruction cannot be delivered the call fails with a 503 carrying ErrCodeMailboxWorkerUnreachable and nothing is removed; the client's default retry policy already retries 5xx responses, so retry again in a moment if it still fails rather than assuming it worked.
func (*EmailService) FinishOAuth ¶
func (s *EmailService) FinishOAuth(ctx context.Context, code, state string, opts ...RequestOption) (*Email, *Response, error)
FinishOAuth exchanges the authorization code for a connected mailbox. It completes both a first connect (answered 201 with the new mailbox) and a EmailService.ReauthOAuth round trip (answered 200 with the renewed one); check the Response status code to tell them apart.
func (*EmailService) Get ¶
func (s *EmailService) Get(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
Get retrieves a single mailbox by ID.
func (*EmailService) GetTrackingDomain ¶ added in v0.3.0
func (s *EmailService) GetTrackingDomain(ctx context.Context, id string, opts ...RequestOption) (*TrackingDomainStatus, *Response, error)
GetTrackingDomain returns the mailbox's stored tracking-domain state plus the CNAME target this install expects. It is read-only and does no DNS work, so it is safe to call on every render; Status is TrackingStatusPending for a domain that has not been re-resolved. Use EmailService.VerifyTrackingDomain for the live check.
func (*EmailService) Hold ¶ added in v0.3.0
func (s *EmailService) Hold(ctx context.Context, id string, opts ...RequestOption) (*SendLifecycleState, *Response, error)
Hold takes the mailbox out of campaign sending until EmailService.Release puts it back, moving it to SendLifecycleReserve. Warmup keeps running. This is the owner's decision: the automatic rest-and-resume logic never touches a held mailbox. Bodyless and idempotent, so holding an already held mailbox simply returns its current state. Installs without the lifecycle engine answer with a 409.
func (*EmailService) List ¶
func (s *EmailService) List(ctx context.Context, params *EmailListParams, opts ...RequestOption) (*Page[Email], error)
List returns a page of connected mailboxes, newest first.
func (*EmailService) PauseWarmup ¶
func (s *EmailService) PauseWarmup(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
PauseWarmup pauses warmup without losing ramp progress. The mailbox stays in its pool, so its health keeps being tracked.
func (*EmailService) ReauthOAuth ¶ added in v0.3.0
func (s *EmailService) ReauthOAuth(ctx context.Context, id string, opts ...RequestOption) (*OAuthStartResult, *Response, error)
ReauthOAuth starts an OAuth round trip that renews the tokens of an existing Gmail or Outlook mailbox after the provider invalidated them (a password change, a revoked grant). The finish leg is the ordinary EmailService.FinishOAuth; the consent must be for the mailbox's own address, and signing in with a different account is refused rather than quietly connecting the wrong mailbox. A successful reconnect keeps every setting, its history and its warmup progress, and never counts against the allowance.
An SMTP/IMAP mailbox is refused with a 400 (use EmailService.UpdateSMTPIMAPCredentials), and a mailbox whose sign-in is held by Warmbly Cloud with a 409. Requires the manage-emails permission.
func (*EmailService) RefreshAuthCheck ¶ added in v0.3.0
func (s *EmailService) RefreshAuthCheck(ctx context.Context, id string, opts ...RequestOption) (*DomainAuthCheck, *Response, error)
RefreshAuthCheck runs the same lookup as EmailService.AuthCheck and records the verdict against every active mailbox on the sending domain, since authentication is a property of the domain rather than of one mailbox. This is how a mailbox blocked by the send gate is unblocked: fix the DNS records, call this, and cold sending and warmup resume on the next scheduled send instead of waiting for the daily background check.
It needs the write scope because recording the verdict is what lifts the gate. Bodyless and derived from public DNS with no caller input, so repeating it converges on the same stored state.
func (*EmailService) Release ¶ added in v0.3.0
func (s *EmailService) Release(ctx context.Context, id string, opts ...RequestOption) (*SendLifecycleState, *Response, error)
Release puts a held or resting mailbox back into automatic management. It lands in SendLifecycleActive, or straight in SendLifecycleResting when warmup is running and still reports the mailbox as throttled or worse, so a release never sends cold mail from a mailbox that warmup can see is struggling; the returned Reason says which. It is also the manual exit from an automatic rest. Bodyless and idempotent.
func (*EmailService) ResumeWarmup ¶
func (s *EmailService) ResumeWarmup(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
ResumeWarmup resumes a paused warmup, shifting the ramp anchor forward so progress continues at the same daily volume.
func (*EmailService) Send ¶
func (s *EmailService) Send(ctx context.Context, id string, params *SendEmailParams, opts ...RequestOption) (*SendResult, *Response, error)
Send sends a one-off message from the given mailbox, dispatched through the mailbox's assigned worker. It requires the send-campaigns scope and an organization. Pass WithIdempotencyKey when you may retry, so a retried call cannot send twice.
func (*EmailService) StartOAuth ¶
func (s *EmailService) StartOAuth(ctx context.Context, provider string, opts ...RequestOption) (*OAuthStartResult, *Response, error)
StartOAuth begins connecting a Gmail or Outlook mailbox and returns the URL to send the user to. Provider is ProviderGmail or ProviderOutlook.
The provider redirects to a Warmbly-hosted page that posts the code and state back to the opener; pass those to EmailService.FinishOAuth.
func (*EmailService) StartWarmup ¶
func (s *EmailService) StartWarmup(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
StartWarmup enables warmup for a mailbox, resuming from the existing ramp progress when it was previously paused, and seeds the warmup task chain immediately rather than waiting for the next reconciler pass.
func (*EmailService) StopWarmup ¶
func (s *EmailService) StopWarmup(ctx context.Context, id string, opts ...RequestOption) (*Email, *Response, error)
StopWarmup disables warmup and clears ramp progress; a later start begins a fresh ramp. Use EmailService.PauseWarmup to keep the progress.
func (*EmailService) SyncStatus ¶ added in v0.3.0
func (s *EmailService) SyncStatus(ctx context.Context, id string, opts ...RequestOption) (*MailboxSync, *Response, error)
SyncStatus reports where the mailbox's import stands, whether fair use is holding it, and the budget it runs under. State is nil until the worker has reported once.
func (*EmailService) Update ¶
func (s *EmailService) Update(ctx context.Context, id string, params *EmailUpdateParams, opts ...RequestOption) (*Email, *Response, error)
Update modifies a mailbox's settings. Changes apply to the next scheduled send, not retroactively.
func (*EmailService) UpdateBehavior ¶ added in v0.3.0
func (s *EmailService) UpdateBehavior(ctx context.Context, id string, params *SendingBehaviorUpdateParams, opts ...RequestOption) (*SendingBehavior, *Response, error)
UpdateBehavior applies a partial update to the mailbox's sending-behavior profile and returns the whole profile. Nil fields keep their stored value. The body is the desired state, so a retry converges on the same profile and no idempotency key is needed.
func (*EmailService) UpdateSMTPIMAPCredentials ¶ added in v0.3.0
func (s *EmailService) UpdateSMTPIMAPCredentials(ctx context.Context, id string, params *SMTPIMAPCredentialsParams, opts ...RequestOption) (*Email, *Response, error)
UpdateSMTPIMAPCredentials replaces an existing SMTP/IMAP mailbox's credentials after a password or server change, validating them live before storing, then clears the authentication error and reactivates the mailbox on its existing worker so it resumes syncing from where it stopped. The address and display name never change. An OAuth mailbox is refused with a 400 (use EmailService.ReauthOAuth). Requires the manage-emails permission.
func (*EmailService) UpdateTrackingDomain ¶
func (s *EmailService) UpdateTrackingDomain(ctx context.Context, id, domain string, opts ...RequestOption) (*TrackingDomainStatus, *Response, error)
UpdateTrackingDomain sets the mailbox's custom tracking subdomain (for example "t.acme.com"), resolves it once and records the verdict. An empty domain clears it and falls back to the shared tracking host.
The value is normalized before it is stored (scheme, path, trailing dot and case are stripped); anything that is still not a bare hostname (an IP, a host with a port, "localhost", a single label) is rejected with a 400. DNS can lag a freshly added record, so a miss is reported as unverified with a reason, not as an error. The record must point at TrackingDomainStatus.CNAMETarget.
func (*EmailService) Verify ¶
func (s *EmailService) Verify(ctx context.Context, email string, opts ...RequestOption) (*VerifyResult, *Response, error)
Verify checks whether a recipient address is deliverable, before anything is ever sent to it, through whichever verifier the workspace uses (its connected provider, else the built-in syntax, MX and SMTP probe). Nothing is stored; use the contacts verification endpoints to record verdicts.
func (*EmailService) VerifyTrackingDomain ¶ added in v0.3.0
func (s *EmailService) VerifyTrackingDomain(ctx context.Context, id string, opts ...RequestOption) (*TrackingDomainStatus, *Response, error)
VerifyTrackingDomain re-resolves the mailbox's saved tracking domain and records the verdict without changing the domain itself. This is how a record that has finished propagating starts being used straight away; the backend also re-checks every custom domain hourly, so this is the impatient path rather than the only one. A transient resolver failure never revokes a verified domain. Bodyless and derived from public DNS, so it needs no idempotency key.
func (*EmailService) WarmupBanStatus ¶
func (s *EmailService) WarmupBanStatus(ctx context.Context, id string, opts ...RequestOption) (*WarmupBanStatus, *Response, error)
WarmupBanStatus reports whether a mailbox has been blocked from the warmup pool, why, and whether the owner can appeal.
type EmailUpdateParams ¶
type EmailUpdateParams struct {
Name *string `json:"name,omitempty"`
SignaturePlain *string `json:"signature_plain,omitempty"`
SignatureHTML *string `json:"signature_html,omitempty"`
SignatureSync *bool `json:"signature_sync,omitempty"`
SignatureCode *bool `json:"signature_code,omitempty"`
// Status is [MailboxStatusActive], [MailboxStatusInactive] or
// [MailboxStatusRevoked]. Setting a mailbox inactive stops its syncing and
// sending within seconds while keeping its settings, history and worker
// assignment; switching it back on resumes where it stopped.
Status *string `json:"status,omitempty"`
// CampaignLimit is the daily cold-campaign cap, 0 to 5000. 30 to 50 a day
// is the safe band; a fresh mailbox should start at 10 to 20 and ramp.
CampaignLimit *int `json:"campaign_limit,omitempty"`
// MinWaitTime is the minimum gap between sends, in seconds.
MinWaitTime *int `json:"min_wait_time,omitempty"`
ReplyTo *string `json:"reply_to,omitempty"`
// Timezone is the mailbox's own IANA zone, such as "America/Denver". Send
// an empty string to clear it, which leaves only the campaign's own window
// applying.
Timezone *string `json:"timezone,omitempty"`
// SaveToSent controls the Sent-folder copy on SMTP/IMAP mailboxes. Turn it
// off when the submission server already files its own copy (Gmail,
// Fastmail and Zoho do), or the folder ends up with two of everything.
// Ignored for OAuth mailboxes.
SaveToSent *bool `json:"save_to_sent,omitempty"`
// Warmup enables or disables warmup. Prefer the explicit lifecycle methods
// ([EmailService.StartWarmup] and friends) unless you are changing warmup
// settings in the same call.
Warmup *bool `json:"warmup,omitempty"`
WarmupBase *int `json:"warmup_base,omitempty"`
WarmupMax *int `json:"warmup_max,omitempty"`
WarmupIncrease *int `json:"warmup_increase,omitempty"`
WarmupReplyRate *int `json:"warmup_reply_rate,omitempty"`
WarmupTag *string `json:"warmup_tag,omitempty"`
WarmupStartTime *string `json:"warmup_start_time,omitempty"`
WarmupEndTime *string `json:"warmup_end_time,omitempty"`
WarmupDays *int `json:"warmup_days,omitempty"`
// Tags replaces the mailbox's tag ids wholesale when non-nil.
Tags []string `json:"tags,omitempty"`
}
EmailUpdateParams are the parameters for updating a mailbox. Unset (nil) fields are left unchanged.
type EngagementBucket ¶ added in v0.3.0
type EngagementBucket struct {
Key string `json:"key"`
Opens int64 `json:"opens"`
Clicks int64 `json:"clicks"`
}
EngagementBucket is one slice of an engagement breakdown: how many distinct contacts opened and clicked from that country, client or device.
type EngagementOrigin ¶ added in v0.3.0
type EngagementOrigin struct {
Client string `json:"client,omitempty"`
DeviceType string `json:"device_type,omitempty"`
OS string `json:"os,omitempty"`
Browser string `json:"browser,omitempty"`
BrowserVersion string `json:"browser_version,omitempty"`
CountryCode string `json:"country_code,omitempty"`
Region string `json:"region,omitempty"`
City string `json:"city,omitempty"`
}
EngagementOrigin is what an open or click said about where it came from. Client names the mail client or image proxy when the user agent does (Gmail, Apple Mail, Outlook); the browser fields describe the rest. The location is resolved from the source network; the address itself is never stored. Every field is empty when unknown.
type EnterpriseInquiryParams ¶
type EnterpriseInquiryParams struct {
CompanyName string `json:"company_name"`
ContactName string `json:"contact_name"`
ContactEmail string `json:"contact_email"`
// EstimatedVolume is expected monthly send volume.
EstimatedVolume *int `json:"estimated_volume,omitempty"`
TeamSize *int `json:"team_size,omitempty"`
Notes string `json:"notes,omitempty"`
}
EnterpriseInquiryParams asks the sales team to get in touch. CompanyName, ContactName and ContactEmail are required.
type Error ¶
type Error struct {
// StatusCode is the HTTP status code of the response.
StatusCode int `json:"-"`
// Type is the machine-readable error family (the API "error" field).
Type string `json:"error"`
// Message is the human-readable description.
Message string `json:"message"`
// Code is a stable, machine-readable error code.
Code string `json:"code"`
// RequestID identifies the request server-side and should be included in
// any support correspondence.
RequestID string `json:"request_id"`
// RetryAfter is the number of seconds to wait before retrying, when the
// server provides it (typically on 429 responses).
RetryAfter int `json:"retry_after,omitempty"`
// Header is the full set of response headers, for inspection.
Header http.Header `json:"-"`
}
Error is the typed error returned for any non-2xx API response. It mirrors the JSON error envelope returned by the Warmbly API, which is the same four fields on every endpoint — there is no nested "details" or per-field validation object to dig through:
{
"error": "Not Found",
"message": "Resource not found.",
"code": "not_found",
"request_id": "0b6f...",
"retry_after": 30
}
"error" and "message" are for people; branch on Error.Code and the HTTP status. "retry_after" appears only where the endpoint has a wait to quote (rate limiting); the client also fills it from the Retry-After header.
The package sentinels (ErrNotFound, ErrUnauthorized, ...) can be matched with errors.Is to branch on the HTTP status without parsing the body, and Error.HasCode on the stable code for the specific condition:
if errors.Is(err, warmbly.ErrNotFound) {
// handle a 404
}
var apiErr *warmbly.Error
if errors.As(err, &apiErr) && apiErr.HasCode(warmbly.ErrCodeStorageLimitReached) {
// the quota, not a malformed request
}
Example ¶
Errors decode into a typed *Error that matches the package sentinels, so you can branch on the status without parsing the body.
package main
import (
"context"
"errors"
"fmt"
"github.com/warmbly/warmbly-go"
)
func main() {
client, _ := warmbly.New(warmbly.WithAPIKey("wmbly_..."))
_, _, err := client.Campaigns.Get(context.Background(), "camp_missing")
switch {
case errors.Is(err, warmbly.ErrNotFound):
fmt.Println("no such campaign")
case errors.Is(err, warmbly.ErrRateLimited):
var apiErr *warmbly.Error
errors.As(err, &apiErr)
fmt.Println("slow down for", apiErr.RetryAfter, "seconds")
case err != nil:
var apiErr *warmbly.Error
if errors.As(err, &apiErr) {
// The request id is what support needs to find the request.
fmt.Printf("%s (request %s)\n", apiErr.Message, apiErr.RequestID)
}
}
}
Output:
func (*Error) HasCode ¶ added in v0.3.0
HasCode reports whether the response carried the given stable error code. It is nil-safe, so it can be used on the result of an errors.As that did not match:
var apiErr *warmbly.Error
errors.As(err, &apiErr)
if apiErr.HasCode(warmbly.ErrCodeNoOrganization) { ... }
Compare against the ErrCode* constants rather than literals: a code is stable where the human-readable message is not.
func (*Error) Is ¶
Is reports whether the error matches target. It enables matching against the package sentinels by HTTP status. The ErrServer sentinel matches any 5xx status.
func (*Error) Temporary ¶
Temporary reports whether the error is likely transient and worth retrying: rate limiting (429) or server errors (5xx).
It is a status-level guess. Two 5xx codes are not transient at all — ErrCodeMailboxProviderNotConfigured and, on the mailbox delete path, ErrCodeMailboxWorkerUnreachable — so check Error.HasCode before building a retry loop around them.
type EventSubscription ¶
type EventSubscription struct {
ID string `json:"id"`
ConnectionID string `json:"connection_id"`
OrganizationID string `json:"organization_id,omitempty"`
// EventType is a webhook event key; see the Event* constants.
EventType string `json:"event_type"`
// Action is a provider action identifier from
// [IntegrationCatalogEntry.ActionTypes].
Action string `json:"action"`
Config json.RawMessage `json:"config,omitempty"`
Enabled bool `json:"enabled"`
UseCase string `json:"use_case,omitempty"`
// AutomationID is set when the subscription is backed by an automation
// flow rather than a single action.
AutomationID *string `json:"automation_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
EventSubscription binds a Warmbly event to an action on a connection.
type EventSubscriptionParams ¶
type EventSubscriptionParams struct {
EventType string `json:"event_type"`
Action string `json:"action"`
Config json.RawMessage `json:"config,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
EventSubscriptionParams creates an event subscription.
type FeatureStatus ¶
type FeatureStatus struct {
Subscription *SubscriptionStatus `json:"subscription"`
CanSendCampaigns bool `json:"can_send_campaigns"`
CanUseWarmup bool `json:"can_use_warmup"`
CanUseUnibox bool `json:"can_use_unibox"`
}
FeatureStatus is the subscription status plus the specific capability gates a client should check before offering an action. Every workspace may warm its mailboxes, so CanUseWarmup is only false where sending is blocked outright.
type FieldMapping ¶
type FieldMapping struct {
ID string `json:"id"`
ConnectionID string `json:"connection_id"`
OrganizationID string `json:"organization_id,omitempty"`
SubscriptionID *string `json:"subscription_id,omitempty"`
// Direction is [SyncPush], [SyncPull] or [SyncBoth].
Direction string `json:"direction,omitempty"`
// ObjectName is the provider object the mapping applies to, for example
// "contact".
ObjectName string `json:"object_name"`
WarmblyField string `json:"warmbly_field"`
ExternalField string `json:"external_field"`
// Transform names an optional value transformation.
Transform string `json:"transform,omitempty"`
// StaticValue writes a constant instead of reading a Warmbly field.
StaticValue string `json:"static_value,omitempty"`
// IsDefault marks a mapping the platform supplied rather than the user.
IsDefault bool `json:"is_default"`
CreatedAt time.Time `json:"created_at"`
}
FieldMapping maps a Warmbly field to a field on the provider.
type FieldMappingInput ¶
type FieldMappingInput struct {
ExternalField string `json:"external_field"`
WarmblyField string `json:"warmbly_field,omitempty"`
Transform string `json:"transform,omitempty"`
StaticValue string `json:"static_value,omitempty"`
}
FieldMappingInput is one mapping in a wholesale replacement.
type FileUpload ¶
type FileUpload struct {
// Filename is the name recorded server-side. It is required.
Filename string
// Content is read to EOF and buffered so the request stays retryable.
Content io.Reader
// ContentType overrides the part's Content-Type. When empty the server
// sniffs the file instead.
ContentType string
}
FileUpload is a file being sent to a multipart endpoint such as campaign attachments or the organization avatar.
type Form ¶ added in v0.3.0
type Form struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
CreatedBy *string `json:"created_by,omitempty"`
// PublicID is the unguessable token in the hosted URL and the embed
// codes. It survives a workspace export/import so installed embeds keep
// working.
PublicID string `json:"public_id"`
// Name is the internal label shown in the dashboard, never to visitors.
Name string `json:"name"`
// Status is one of the FormStatus* constants.
Status string `json:"status"`
// Fields are the blocks in render order. A new form is seeded with first
// name, last name and a required email.
Fields []FormField `json:"fields"`
Design FormDesign `json:"design"`
// SuccessMessage is shown after a submit unless RedirectURL is set.
SuccessMessage string `json:"success_message"`
// RedirectURL, when set, sends the visitor to your own thank-you page
// instead of showing SuccessMessage.
RedirectURL string `json:"redirect_url"`
// CampaignID is the campaign new contacts are enrolled in on submit.
// Sending still follows that campaign's own schedule and limits; a form
// never causes immediate mail.
CampaignID *string `json:"campaign_id,omitempty"`
// CategoryIDs are the contact categories every submitted contact is
// filed under.
CategoryIDs []string `json:"category_ids"`
// AllowedDomains restricts which sites may embed the form; a domain
// covers its subdomains. Empty allows any site. The hosted link works
// either way.
AllowedDomains []string `json:"allowed_domains"`
// CaptchaEnabled adds a Cloudflare Turnstile challenge. It only takes
// effect when [FormsConfig.CaptchaAvailable] is true for the instance.
CaptchaEnabled bool `json:"captcha_enabled"`
// LogoURL, CoverURL and BackgroundURL are the public object URLs of the
// uploaded brand assets; empty when none is set. Change them with
// [FormService.UploadAsset] and [FormService.DeleteAsset], not Update.
LogoURL string `json:"logo_url"`
CoverURL string `json:"cover_url"`
BackgroundURL string `json:"background_url"`
// ViewsCount and SubmissionsCount are lifetime counters, kept forever.
ViewsCount int64 `json:"views_count"`
SubmissionsCount int64 `json:"submissions_count"`
LastSubmissionAt *time.Time `json:"last_submission_at,omitempty"`
// PublishedAt is when the form last went from unpublished to published.
PublishedAt *time.Time `json:"published_at,omitempty"`
// StartsCount, IdentifiedCount and Trend are rollups over the last 14
// days of funnel events. They are populated by [FormService.List] only;
// other reads leave them zero and Trend nil. Trend has one entry per
// day, oldest first.
StartsCount int64 `json:"starts_count"`
IdentifiedCount int64 `json:"identified_count"`
Trend []int64 `json:"trend,omitempty"`
// custom forms domain when it has one and the shared forms host
// otherwise. Empty when the install has no forms host configured.
ShareURL string `json:"share_url,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Form is a hosted lead-capture form: an ordered block list plus a theme, published at a public URL and embeddable on any site. A submission that carries an email creates or updates a contact, files it under CategoryIDs and, when CampaignID is set, enrolls it as a lead there.
type FormCreateParams ¶ added in v0.3.0
type FormCreateParams struct {
// Name is required, at most 120 characters.
Name string `json:"name"`
}
FormCreateParams names a new form. It is created as a draft seeded with first name, last name and email fields and the default success message; everything else is set with FormService.Update.
type FormDesign ¶ added in v0.3.0
type FormDesign struct {
// FontFamily is one of the FormFont* constants.
FontFamily string `json:"font_family,omitempty"`
PageBackground string `json:"page_background,omitempty"`
FormBackground string `json:"form_background,omitempty"`
TextColor string `json:"text_color,omitempty"`
LabelColor string `json:"label_color,omitempty"`
InputBackground string `json:"input_background,omitempty"`
InputBorderColor string `json:"input_border_color,omitempty"`
InputTextColor string `json:"input_text_color,omitempty"`
PlaceholderColor string `json:"placeholder_color,omitempty"`
AccentColor string `json:"accent_color,omitempty"`
ButtonBackground string `json:"button_background,omitempty"`
ButtonTextColor string `json:"button_text_color,omitempty"`
// ButtonText is the submit button's caption.
ButtonText string `json:"button_text,omitempty"`
// ButtonSize is one of the FormSize* constants.
ButtonSize string `json:"button_size,omitempty"`
ButtonFullWidth bool `json:"button_full_width,omitempty"`
// BorderRadius is clamped by the server to 0-24 pixels.
BorderRadius *int `json:"border_radius,omitempty"`
// MaxWidth is clamped by the server to 320-960 pixels (default 560).
MaxWidth *int `json:"max_width,omitempty"`
// Spacing is one of the FormSpacing* constants.
Spacing string `json:"spacing,omitempty"`
Shadow *bool `json:"shadow,omitempty"`
// Theme records which preset seeded the current colors. Renderers never
// read it, so any short lowercase slug is accepted.
Theme string `json:"theme,omitempty"`
// Layout is one of the FormLayout* constants.
Layout string `json:"layout,omitempty"`
// Mode is one of the FormMode* constants.
Mode string `json:"mode,omitempty"`
// PageBackgroundEnd turns the page background into a vertical gradient
// from PageBackground to this color.
PageBackgroundEnd string `json:"page_background_end,omitempty"`
// Align is [FormAlignLeft] or [FormAlignCenter].
Align string `json:"align,omitempty"`
// ShowProgress shows a progress bar on multi-page forms.
ShowProgress *bool `json:"show_progress,omitempty"`
// BackgroundSize (a FormBackgroundSize* constant) and BackgroundOverlay
// (0-100) style the uploaded background image: the overlay veils it with
// the page color so text on top stays legible.
BackgroundSize string `json:"background_size,omitempty"`
BackgroundOverlay *int `json:"background_overlay,omitempty"`
// The header is an optional bar carrying the logo and a title. A header
// with neither is skipped on the live page. HeaderBackground and
// HeaderSticky apply only to the page placement.
HeaderEnabled *bool `json:"header_enabled,omitempty"`
HeaderTitle string `json:"header_title,omitempty"`
HeaderBackground string `json:"header_background,omitempty"`
// HeaderPlacement is one of the FormHeaderPlacement* constants.
HeaderPlacement string `json:"header_placement,omitempty"`
// HeaderAlign is [FormAlignLeft], [FormAlignCenter] or [FormAlignBetween].
HeaderAlign string `json:"header_align,omitempty"`
HeaderSticky *bool `json:"header_sticky,omitempty"`
HeaderShowLogo *bool `json:"header_show_logo,omitempty"`
// CoverTitle and CoverSubtitle are drawn over the split layout's cover
// panel.
CoverTitle string `json:"cover_title,omitempty"`
CoverSubtitle string `json:"cover_subtitle,omitempty"`
// LogoSize is one of the FormSize* constants; LogoPosition one of the
// FormLogoPosition* constants.
LogoSize string `json:"logo_size,omitempty"`
LogoPosition string `json:"logo_position,omitempty"`
}
FormDesign is the theme rendered around the fields. Every value is optional and an unset one falls back to the renderer's default, so a sparse design is normal. Colors are "#rrggbb" or "transparent".
type FormField ¶ added in v0.3.0
type FormField struct {
// ID is a builder-chosen slug (lowercase letters, digits, "_" and "-",
// up to 40 characters), unique within the form and stable across edits.
// Submissions key their answers by it.
ID string `json:"id"`
// Type is one of the FormFieldType* constants.
Type string `json:"type"`
// Label is required for every input type except hidden. For a page
// break it is the page title.
Label string `json:"label"`
Placeholder string `json:"placeholder,omitempty"`
HelpText string `json:"help_text,omitempty"`
Required bool `json:"required"`
// Options are the choices of a select, radio or checkboxes block (1 to
// 50, each unique). Other types ignore them.
Options []string `json:"options,omitempty"`
// MapTo names the contact column the answer fills (a FormMapTo*
// constant). Empty means the answer lands in the contact's custom fields
// under the field's label.
MapTo string `json:"map_to,omitempty"`
// Value is the constant a hidden field submits, or the body text of a
// paragraph block.
Value string `json:"value,omitempty"`
// Width is [FormFieldWidthFull] (the default) or [FormFieldWidthHalf].
Width string `json:"width,omitempty"`
// Rows is the visible height of a textarea (0 to 20; 0 uses the default).
Rows int `json:"rows,omitempty"`
}
FormField is one block on a form.
type FormFunnelPage ¶ added in v0.3.0
type FormFunnelPage struct {
// PageIndex is zero-based.
PageIndex int `json:"page_index"`
// Title is the page-break label, or a generated one when unset.
Title string `json:"title"`
Reached int64 `json:"reached"`
CompletedFrom int64 `json:"completed_from"`
}
FormFunnelPage is one row of the page funnel: how many visitors reached the page, and how many of those went on to submit.
type FormIdentifiedVisitor ¶ added in v0.3.0
type FormIdentifiedVisitor struct {
ContactID string `json:"contact_id"`
Name string `json:"name"`
Email string `json:"email"`
LastSeen time.Time `json:"last_seen"`
// FurthestPage is the zero-based index of the last page reached.
FurthestPage int `json:"furthest_page"`
Completed bool `json:"completed"`
// Campaign names the campaign whose email brought this contact here,
// when there was one.
Campaign string `json:"campaign,omitempty"`
}
FormIdentifiedVisitor is a contact who opened the form through a personalized link, and how far they got.
type FormLink ¶ added in v0.3.0
type FormLink struct {
URL string `json:"url"`
}
FormLink is a personalized form URL for one contact: the hosted page URL with a per-contact ticket (?t=...). Opening it pre-fills the contact's mapped fields and attributes the visit and any submission to that contact even if they type a different email. Holding the link is the identity, so treat it like an unsubscribe link.
type FormService ¶ added in v0.3.0
type FormService service
FormService manages hosted lead-capture forms: their definition and theme, their submissions and funnel analytics, per-contact personalized links, uploaded brand assets and the workspace-wide custom forms domain.
A form is built here but served elsewhere: the public page (/f/:public_id), its submit endpoint and the embed loader (/forms.js) live on the standalone forms host (FORMS_DOMAIN), take no authentication and are not part of this SDK. Form.ShareURL points at that host.
Form routes take the contact scopes (read_contacts to view, write_contacts to change), since a form exists only to create and update contacts. The /forms/domain routes additionally need the manage_settings organization permission for session (JWT) callers.
func (*FormService) Config ¶ added in v0.3.0
func (s *FormService) Config(ctx context.Context, opts ...RequestOption) (*FormsConfig, *Response, error)
Config reports the instance's forms deployment: the public forms origin and whether a captcha provider is available.
func (*FormService) Create ¶ added in v0.3.0
func (s *FormService) Create(ctx context.Context, params *FormCreateParams, opts ...RequestOption) (*Form, *Response, error)
Create makes a new draft form seeded with first name, last name and email fields. Configure and publish it with FormService.Update.
func (*FormService) Delete ¶ added in v0.3.0
func (s *FormService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete permanently removes a form together with its submissions, link tickets and funnel events. Contacts it created are kept. To take a form offline without losing anything, set its status to FormStatusArchived instead.
func (*FormService) DeleteAsset ¶ added in v0.3.0
func (s *FormService) DeleteAsset(ctx context.Context, id, kind string, opts ...RequestOption) (*Form, *Response, error)
DeleteAsset removes a brand image and returns the updated form. kind is one of the FormAsset* constants. Removing an asset that is not set succeeds.
func (*FormService) DeleteSubmission ¶ added in v0.3.0
func (s *FormService) DeleteSubmission(ctx context.Context, id, submissionID string, opts ...RequestOption) (*Response, error)
DeleteSubmission removes one submission. The contact it created or updated is kept.
func (*FormService) Domain ¶ added in v0.3.0
func (s *FormService) Domain(ctx context.Context, opts ...RequestOption) (*FormsDomainStatus, *Response, error)
Domain reads the stored state of the workspace's custom forms domain without doing any DNS work. A stored but unverified domain reports FormsDomainStatusPending; use FormService.VerifyDomain for a live verdict.
func (*FormService) Get ¶ added in v0.3.0
func (s *FormService) Get(ctx context.Context, id string, opts ...RequestOption) (*Form, *Response, error)
Get retrieves a single form by ID.
func (*FormService) List ¶ added in v0.3.0
func (s *FormService) List(ctx context.Context, opts ...RequestOption) ([]Form, *Response, error)
List returns every form in the workspace. There is no pagination or filtering; a workspace holds at most 100 forms. This is the only read that fills the 14-day rollups (Form.StartsCount, Form.IdentifiedCount and Form.Trend).
func (*FormService) ListSubmissions ¶ added in v0.3.0
func (s *FormService) ListSubmissions(ctx context.Context, id string, params *FormSubmissionListParams, opts ...RequestOption) (*Page[FormSubmission], error)
ListSubmissions returns a page of the form's submissions, newest first. Paging is by timestamp rather than opaque cursor: the returned page's NextCursor is the RFC 3339 created_at of its last row, and Page.Next and Page.All pass it back as the before parameter. Pagination.Total is never set; use Form.SubmissionsCount for the lifetime count.
func (*FormService) MintLink ¶ added in v0.3.0
func (s *FormService) MintLink(ctx context.Context, id, contactID string, opts ...RequestOption) (*FormLink, *Response, error)
MintLink returns the personalized URL of the form for one contact. It is a GET on top of an upsert: the first call creates the contact's ticket and every later call returns the same one, so retries are safe. It needs the contact write scope, since minting writes a link row. It fails when the install has no forms host configured.
func (*FormService) SetDomain ¶ added in v0.3.0
func (s *FormService) SetDomain(ctx context.Context, domain string, opts ...RequestOption) (*FormsDomainStatus, *Response, error)
SetDomain stores a custom forms domain (a subdomain of the domain you send from, for example "forms.acme.com") and immediately resolves it, so saving and verifying are one step. An empty domain clears it back to the shared host. An unresolved record is not an error: the domain stays stored and unverified with a Status explaining why, and links keep using the shared host until it verifies. The server re-checks hourly on its own.
This is a workspace-wide setting; session callers need manage_settings.
func (*FormService) Stats ¶ added in v0.3.0
func (s *FormService) Stats(ctx context.Context, id, window string, opts ...RequestOption) (*FormStats, *Response, error)
Stats returns the form's funnel analytics over a trailing window. window is one of the FormStatsRange* constants; empty means FormStatsRange30Days.
func (*FormService) Update ¶ added in v0.3.0
func (s *FormService) Update(ctx context.Context, id string, params *FormUpdateParams, opts ...RequestOption) (*Form, *Response, error)
Update modifies a form. Edits to a published form go live immediately. Moving Status to published stamps Form.PublishedAt and requires at least one non-hidden input field.
func (*FormService) UploadAsset ¶ added in v0.3.0
func (s *FormService) UploadAsset(ctx context.Context, id, kind string, file *FileUpload, opts ...RequestOption) (*Form, *Response, error)
UploadAsset uploads a brand image and returns the updated form. kind is one of the FormAsset* constants; see them for the size caps. The file must be a PNG or JPG, sent as the multipart field "file". Uploading over an existing asset replaces it.
func (*FormService) VerifyDomain ¶ added in v0.3.0
func (s *FormService) VerifyDomain(ctx context.Context, opts ...RequestOption) (*FormsDomainStatus, *Response, error)
VerifyDomain re-resolves the stored custom forms domain and records the verdict. Call it after a DNS change instead of waiting for the hourly re-check. Session callers need manage_settings.
type FormStats ¶ added in v0.3.0
type FormStats struct {
Totals FormStatsTotals `json:"totals"`
// Daily has one entry per day of the window, oldest first.
Daily []FormStatsDay `json:"daily"`
// Pages is the page funnel; a single-page form has one row.
Pages []FormFunnelPage `json:"pages"`
// Sources, Countries, Devices and Campaigns are the top buckets (at most
// eight each) keyed by referrer domain, ISO country code, device class
// (desktop, mobile, tablet or unknown) and campaign name.
Sources []FormStatsBucket `json:"sources"`
Countries []FormStatsBucket `json:"countries"`
Devices []FormStatsBucket `json:"devices"`
Campaigns []FormStatsBucket `json:"campaigns"`
// Identified lists the most recent contacts (up to 25) who opened the
// form through a personalized link.
Identified []FormIdentifiedVisitor `json:"identified"`
}
FormStats is the analytics payload for one form over a window: funnel totals, a daily series, per-page drop-off, traffic breakdowns and the contacts identified through personalized links. Location is resolved to country only; visitor IPs are never stored.
type FormStatsBucket ¶ added in v0.3.0
FormStatsBucket is one row of a breakdown.
type FormStatsDay ¶ added in v0.3.0
type FormStatsDay struct {
// Date is the calendar day as YYYY-MM-DD.
Date string `json:"date"`
Views int64 `json:"views"`
Starts int64 `json:"starts"`
Submissions int64 `json:"submissions"`
}
FormStatsDay is one day of the funnel series.
type FormStatsTotals ¶ added in v0.3.0
type FormStatsTotals struct {
Views int64 `json:"views"`
// Starts counts visitors who interacted with a field.
Starts int64 `json:"starts"`
Submissions int64 `json:"submissions"`
// CompletionRate is submissions over views, 0 to 1.
CompletionRate float64 `json:"completion_rate"`
// IdentifiedVisitors counts distinct contacts seen through a
// personalized link.
IdentifiedVisitors int64 `json:"identified_visitors"`
}
FormStatsTotals are the funnel counts for the whole window.
type FormSubmission ¶ added in v0.3.0
type FormSubmission struct {
ID string `json:"id"`
FormID string `json:"form_id"`
OrganizationID string `json:"organization_id"`
// ContactID is the contact the submission created or updated, or nil
// when the form has no email field.
ContactID *string `json:"contact_id,omitempty"`
// CampaignID is the campaign whose email carried the personalized link
// the visitor arrived through, when there was one.
CampaignID *string `json:"campaign_id,omitempty"`
// Data holds every answer keyed by [FormField.ID]. A checkboxes block
// decodes as a []any of strings; every other input as a string.
Data map[string]any `json:"data"`
// SourceURL is the page the form was submitted from (the host page for
// an embed, the hosted page otherwise).
SourceURL string `json:"source_url"`
CreatedAt time.Time `json:"created_at"`
// ContactEmail, ContactName and CampaignName are display summaries of
// the linked records, resolved at read time; empty when unlinked.
ContactEmail string `json:"contact_email,omitempty"`
ContactName string `json:"contact_name,omitempty"`
CampaignName string `json:"campaign_name,omitempty"`
}
FormSubmission is one public submit, kept verbatim.
type FormSubmissionListParams ¶ added in v0.3.0
type FormSubmissionListParams struct {
// Limit is the page size, 1 to 100. Zero uses the server default of 50.
Limit int
// Before returns only submissions created strictly before this instant.
// Pass the previous page's last CreatedAt to walk backwards in time;
// [Page.Next] and [Page.All] do this for you.
Before *time.Time
}
FormSubmissionListParams control FormService.ListSubmissions. Submissions are keyset-paginated newest first on created_at rather than by opaque cursor.
type FormSubmittedPayload ¶ added in v0.3.0
type FormSubmittedPayload struct {
FormID string `json:"form_id"`
FormName string `json:"form_name"`
// SubmissionID is the stored submission, which the forms REST endpoint
// serves verbatim.
SubmissionID string `json:"submission_id"`
// Data is the answers keyed by field id. Values keep the type the field
// collected, so a multi-select arrives as a list and a number as a number.
Data map[string]any `json:"data"`
// SourceURL is the page the form was submitted from, when the embed
// reported one.
SourceURL string `json:"source_url,omitempty"`
// ContactID is set when the submission carried a usable email and so
// created or matched a contact. The mapped contact columns ride alongside
// it, flat, so an automation reads {{.contact_email}} without walking
// Data.
ContactID string `json:"contact_id,omitempty"`
ContactEmail string `json:"contact_email,omitempty"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Company string `json:"company,omitempty"`
Phone string `json:"phone,omitempty"`
// CampaignID is the campaign the form enrolls submitters into, when it
// does.
CampaignID string `json:"campaign_id,omitempty"`
}
FormSubmittedPayload is the EventFormSubmitted body.
Unlike the realtime gateway's form event, which carries ids only, the webhook carries the answers: the delivery is already authenticated to one endpoint by its signature, so there is no permission left to enforce at read time.
type FormUpdateParams ¶ added in v0.3.0
type FormUpdateParams struct {
Name *string `json:"name,omitempty"`
// Status moves the form through its lifecycle (FormStatus* constants).
// Publishing requires at least one non-hidden input field.
Status *string `json:"status,omitempty"`
// Fields replaces the block list. Field IDs must stay stable across
// edits or existing submissions lose their labels.
Fields *[]FormField `json:"fields,omitempty"`
// Design replaces the whole theme; it is not merged with the stored one.
Design *FormDesign `json:"design,omitempty"`
// SuccessMessage is capped at 2000 characters; an empty string resets it
// to the server default.
SuccessMessage *string `json:"success_message,omitempty"`
// RedirectURL must be an absolute http(s) URL; an empty string clears it.
RedirectURL *string `json:"redirect_url,omitempty"`
// CampaignID enrolls new contacts in a campaign on submit. To detach the
// form from its campaign set ClearCampaign instead: a nil pointer means
// "leave as is".
CampaignID *string `json:"campaign_id,omitempty"`
// ClearCampaign sends campaign_id as JSON null, detaching the campaign.
// It wins over CampaignID when both are set.
ClearCampaign bool `json:"-"`
CategoryIDs *[]string `json:"category_ids,omitempty"`
AllowedDomains *[]string `json:"allowed_domains,omitempty"`
CaptchaEnabled *bool `json:"captcha_enabled,omitempty"`
}
FormUpdateParams is the PATCH payload for FormService.Update. Nil fields are left untouched. Fields, Design, CategoryIDs and AllowedDomains replace their whole value when set (send the complete list or theme, not a diff), so an empty slice clears the list.
func (FormUpdateParams) MarshalJSON ¶ added in v0.3.0
func (p FormUpdateParams) MarshalJSON() ([]byte, error)
MarshalJSON emits campaign_id as an explicit null when ClearCampaign is set, which is how the server distinguishes "detach" from "unchanged".
type FormsConfig ¶ added in v0.3.0
type FormsConfig struct {
// BaseURL is the origin of the standalone forms host, for example
// "https://forms.example.com"; empty when FORMS_DOMAIN is not configured,
// in which case no form can be served.
BaseURL string `json:"base_url"`
// CaptchaAvailable reports whether the operator configured a captcha
// provider, which [Form.CaptchaEnabled] needs to take effect.
CaptchaAvailable bool `json:"captcha_available"`
}
FormsConfig describes what this instance can do with forms, so a builder never offers a switch that cannot work.
type FormsDomainStatus ¶ added in v0.3.0
type FormsDomainStatus struct {
// FormsDomain is the stored custom host, for example "forms.acme.com";
// empty when none is set.
FormsDomain string `json:"forms_domain"`
FormsDomainVerified bool `json:"forms_domain_verified"`
FormsDomainVerifiedAt *time.Time `json:"forms_domain_verified_at"`
// CNAMETarget is the value to put in the CNAME record: this install's
// shared forms host. Empty means the install has none, so nothing can
// verify.
CNAMETarget string `json:"cname_target"`
// Status is one of the FormsDomainStatus* constants.
Status string `json:"status"`
// Message is a human-readable explanation of Status.
Message string `json:"message"`
// Observed is what DNS actually returned for the domain, so a typo can
// be spotted by comparing it with CNAMETarget.
Observed string `json:"observed,omitempty"`
// FormsHostUnresolvable reports that the install's own forms host does
// not resolve, an operator problem rather than the customer's record.
FormsHostUnresolvable bool `json:"forms_host_unresolvable"`
}
FormsDomainStatus is the state of the workspace's custom forms domain, shaped like TrackingDomainStatus. Only a verified domain is used to build form URLs; until then every link stays on the shared forms host.
type GatewayTicket ¶
type GatewayTicket struct {
// URL is the websocket endpoint with the ticket already embedded, so it can
// be dialed as-is.
URL string `json:"url"`
// ExpiresIn is the ticket's lifetime in seconds.
ExpiresIn float64 `json:"expires_in"`
}
GatewayTicket is a short-lived, single-use credential for opening a gateway connection from a browser session.
type Generation ¶
type Generation struct {
Text string `json:"text"`
// CreditsCharged is what this call cost, including any usage overage;
// CreditsRemaining is the workspace balance afterwards.
CreditsCharged int `json:"credits_charged"`
CreditsRemaining int `json:"credits_remaining"`
TokensUsed int `json:"tokens_used"`
Model string `json:"model"`
}
Generation is the result of an AI writing call.
type GenerationService ¶
type GenerationService service
GenerationService writes and rewrites campaign copy with AI, grounded in the workspace voice profile and any enabled AISkill playbooks.
Every call here spends AI credits and returns the remaining balance, so a caller can surface cost without a second request. None of them send anything.
func (*GenerationService) AIVariable ¶
func (s *GenerationService) AIVariable(ctx context.Context, params *AIVariableParams, opts ...RequestOption) (*Generation, *Response, error)
AIVariable previews an AI variable block against a single contact. A prompt that renders empty against the contact costs nothing.
func (*GenerationService) Edit ¶
func (s *GenerationService) Edit(ctx context.Context, params *EditParams, opts ...RequestOption) (*Generation, *Response, error)
Edit rewrites a passage according to an instruction.
func (*GenerationService) Write ¶
func (s *GenerationService) Write(ctx context.Context, params *WriteParams, opts ...RequestOption) (*Generation, *Response, error)
Write generates a new piece of copy.
type Group ¶
type Group struct {
ID string `json:"id"`
Title string `json:"title"`
Color string `json:"color"`
// Position is the group's index in its ordered set.
Position int32 `json:"position"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Group is a user-scoped label: a campaign folder, a mailbox tag or a contact category. See GroupService.
type GroupCreateParams ¶
GroupCreateParams creates a group.
type GroupOrder ¶
GroupOrder is one group's position after a reorder.
type GroupService ¶
type GroupService struct {
// contains filtered or unexported fields
}
GroupService manages the three ordered label sets that organize the rest of the workspace:
- Folders group campaigns.
- Tags group mailboxes, and are what a campaign's tag-based sender strategy selects on.
- Categories group contacts, and double as unified-inbox conversation labels.
Reach them as client.Folders, client.Tags and client.Categories. They share this type because the three endpoints are identical apart from their path.
There is no list endpoint: the current set rides along on the caller's profile, in User.Folders, User.Tags and User.Categories. Read it with AuthService.Me.
func (*GroupService) Create ¶
func (s *GroupService) Create(ctx context.Context, params *GroupCreateParams, opts ...RequestOption) (*Group, *Response, error)
Create adds a group, appended to the end of the set.
func (*GroupService) Delete ¶
func (s *GroupService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete removes a group. What it labeled keeps existing, unlabeled.
func (*GroupService) Move ¶
func (s *GroupService) Move(ctx context.Context, id string, position int32, opts ...RequestOption) ([]GroupOrder, *Response, error)
Move reorders a group to the given zero-based position and returns the new order of the whole set.
func (*GroupService) Update ¶
func (s *GroupService) Update(ctx context.Context, id string, params *GroupUpdateParams, opts ...RequestOption) (*Group, *Response, error)
Update renames or recolors a group.
type GroupUpdateParams ¶
type GroupUpdateParams struct {
Title *string `json:"title,omitempty"`
Color *string `json:"color,omitempty"`
}
GroupUpdateParams renames or recolors a group. Nil fields are unchanged.
type HourlyStat ¶
type HourlyStat struct {
// Hour is 0-23 in the organization timezone.
Hour int `json:"hour"`
Sent int64 `json:"sent"`
Opens int64 `json:"opens"`
Clicks int64 `json:"clicks"`
Replies int64 `json:"replies"`
}
HourlyStat is one hour of engagement within a day.
type Identity ¶
type Identity struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Name string `json:"name"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
OrganizationID *string `json:"organization_id,omitempty"`
OrganizationName string `json:"organization_name,omitempty"`
// AuthType is [AuthTypeAPIKey], [AuthTypeOAuth] or [AuthTypeJWT].
AuthType string `json:"auth_type"`
// Scopes lists the granted API scope names for an API key or OAuth token.
// It is empty for a session, which carries organization role permissions
// instead.
Scopes []string `json:"scopes"`
}
Identity is who the current credential is and what workspace it acts on. Every credential can read it, which makes it the right call for an integration to validate a connection and label it.
type ImportColumnMapping ¶
type ImportColumnMapping struct {
Index int `json:"index"`
// Target is one of the ImportTarget* constants, or "custom:<key>".
Target string `json:"target"`
// CustomKey is the custom field an [ImportTargetCustom] column writes to.
// It may use letters, numbers, underscores, spaces and dashes.
CustomKey string `json:"custom_key,omitempty"`
// VerificationProvider names the vocabulary of an
// [ImportTargetVerificationStatus] column (a VerificationProvider*
// constant). Empty recognizes each value by itself.
VerificationProvider string `json:"verification_provider,omitempty"`
}
ImportColumnMapping maps the column at Index to a contact field. The index is zero-based and matches ContactImportPreview.Columns.
type ImportRowError ¶
type ImportRowError struct {
Line int `json:"line"`
Email string `json:"email,omitempty"`
Values []string `json:"values,omitempty"`
Reason string `json:"reason"`
}
ImportRowError is a row that could not be imported. Line is the 1-based index into the source file, after the header when there was one.
type InstanceInfo ¶ added in v0.3.0
type InstanceInfo struct {
SelfHosted bool `json:"self_hosted"`
// Version is the release tag and Commit the short commit it was built
// from.
Version string `json:"version,omitempty"`
Commit string `json:"commit,omitempty"`
// UpdateAvailable is true when Latest is newer than Version.
UpdateAvailable bool `json:"update_available"`
// Latest is the newest published release, when the instance has checked.
Latest *InstanceRelease `json:"latest,omitempty"`
// CheckedAt is when the instance last looked for a release.
CheckedAt *time.Time `json:"checked_at,omitempty"`
}
InstanceInfo is which Warmbly a self-hosted instance runs and whether a newer release exists. A hosted deployment answers SelfHosted false and nothing else. Applying an update is an admin-panel action, not an API call.
type InstanceRelease ¶ added in v0.3.0
type InstanceRelease struct {
Tag string `json:"tag"`
HTMLURL string `json:"html_url,omitempty"`
PublishedAt time.Time `json:"published_at,omitempty"`
}
InstanceRelease is one published release.
type IntegrationCatalogEntry ¶
type IntegrationCatalogEntry struct {
// Provider is one of the Provider* constants.
Provider string `json:"provider"`
Name string `json:"name"`
Tagline string `json:"tagline,omitempty"`
// Category groups the provider: "crm", "automation", "notifications",
// "meetings", "data" or "verification".
Category string `json:"category,omitempty"`
DocsURL string `json:"docs_url,omitempty"`
// AuthMethod is "oauth", "api_key" or "webhook".
AuthMethod string `json:"auth_method"`
BadgeColor string `json:"badge_color,omitempty"`
Beta bool `json:"beta"`
// WebhookHint is shown for webhook-URL and inbound providers.
WebhookHint string `json:"webhook_hint,omitempty"`
// Highlights are short "what you get" bullets.
Highlights []string `json:"highlights,omitempty"`
// Scopes are the OAuth scopes requested at authorize time.
Scopes []string `json:"scopes,omitempty"`
// Events are the Warmbly events this provider can react to, and
// ActionTypes the actions it can actually perform.
Events []string `json:"events,omitempty"`
ActionTypes []string `json:"action_types,omitempty"`
// SupportsPush reports whether contacts can be pushed to this provider on
// demand.
SupportsPush bool `json:"supports_push"`
// Configured reports whether this deployment has credentials for the
// provider, so an unconfigured one can be greyed out rather than failing
// at connect time.
Configured bool `json:"configured"`
// Capability is the provider's raw capability descriptor, when it has one.
Capability json.RawMessage `json:"capability,omitempty"`
}
IntegrationCatalogEntry describes one connectable provider.
type IntegrationConnection ¶
type IntegrationConnection struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
// Provider is one of the Provider* constants.
Provider string `json:"provider"`
Label string `json:"label"`
// Status is one of the Connection* constants.
Status string `json:"status"`
// AuthMethod is "oauth", "api_key" or "webhook".
AuthMethod string `json:"auth_method"`
// DisplayFields are the non-secret connection details worth showing.
DisplayFields json.RawMessage `json:"display_fields,omitempty"`
// ConfigCapabilities is the per-connection capability snapshot: selected
// objects, enabled use cases, picker selections. It never holds secrets.
ConfigCapabilities json.RawMessage `json:"config_capabilities,omitempty"`
// SyncDirection is [SyncPush], [SyncPull] or [SyncBoth].
SyncDirection string `json:"sync_direction"`
ConnectedByUserID *string `json:"connected_by_user_id,omitempty"`
ExternalAccountID string `json:"external_account_id,omitempty"`
ExternalAccountName string `json:"external_account_name,omitempty"`
GrantedScopes []string `json:"granted_scopes,omitempty"`
TokenExpiresAt *time.Time `json:"token_expires_at,omitempty"`
// Health is "unknown", "healthy", "degraded" or "down".
Health string `json:"health"`
HealthDetail *string `json:"health_detail,omitempty"`
HealthCheckedAt *time.Time `json:"health_checked_at,omitempty"`
LastSyncedAt *time.Time `json:"last_synced_at,omitempty"`
LastError *string `json:"last_error,omitempty"`
LastErrorAt *time.Time `json:"last_error_at,omitempty"`
// InboundWebhookURL is where an inbound provider should POST. It embeds a
// rotatable per-connection secret, so treat it as a credential.
InboundWebhookURL string `json:"inbound_webhook_url,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
IntegrationConnection is one connected third-party account.
type IntegrationService ¶
type IntegrationService service
IntegrationService manages third-party connections: the provider catalog, connected accounts, the events each connection reacts to, field mappings, sync history and on-demand contact pushes.
Connecting an OAuth provider is a browser flow. Start it with IntegrationService.StartOAuth, send the user to the returned URL, and finish it with IntegrationService.FinishOAuth once the popup posts the code back. Those two calls are session-only.
func (*IntegrationService) Bookings ¶
func (s *IntegrationService) Bookings(ctx context.Context, opts ...RequestOption) ([]Meeting, *Response, error)
Bookings returns meetings from connected scheduling providers. It is the integration-scoped view of the same data MeetingService.List returns.
func (*IntegrationService) Catalog ¶
func (s *IntegrationService) Catalog(ctx context.Context, opts ...RequestOption) ([]IntegrationCatalogEntry, *Response, error)
Catalog returns every connectable provider.
func (*IntegrationService) Connect ¶
func (s *IntegrationService) Connect(ctx context.Context, params *ConnectParams, opts ...RequestOption) (*IntegrationConnection, *Response, error)
Connect creates a connection for an API-key or webhook provider.
func (*IntegrationService) Connection ¶
func (s *IntegrationService) Connection(ctx context.Context, id string, opts ...RequestOption) (*ConnectionDetail, *Response, error)
Connection returns one connection with its event subscriptions and recent sync runs.
func (*IntegrationService) Connections ¶
func (s *IntegrationService) Connections(ctx context.Context, opts ...RequestOption) ([]IntegrationConnection, *Response, error)
Connections returns the workspace's connected accounts.
func (*IntegrationService) CreateEvent ¶
func (s *IntegrationService) CreateEvent(ctx context.Context, id string, params *EventSubscriptionParams, opts ...RequestOption) (*EventSubscription, *Response, error)
CreateEvent subscribes a connection to a Warmbly event.
func (*IntegrationService) DeleteEvent ¶
func (s *IntegrationService) DeleteEvent(ctx context.Context, id, eventID string, opts ...RequestOption) (*Response, error)
DeleteEvent removes an event subscription.
func (*IntegrationService) Disconnect ¶
func (s *IntegrationService) Disconnect(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Disconnect removes a connection and its stored credentials.
func (*IntegrationService) Events ¶
func (s *IntegrationService) Events(ctx context.Context, id string, opts ...RequestOption) ([]EventSubscription, *Response, error)
Events returns a connection's event subscriptions.
func (*IntegrationService) FieldMappings ¶
func (s *IntegrationService) FieldMappings(ctx context.Context, id string, opts ...RequestOption) ([]FieldMapping, *Response, error)
FieldMappings returns a connection's field mappings.
func (*IntegrationService) FinishOAuth ¶
func (s *IntegrationService) FinishOAuth(ctx context.Context, code, state string, opts ...RequestOption) (*IntegrationConnection, *Response, error)
FinishOAuth exchanges the authorization code the provider redirected back with for a stored connection.
func (*IntegrationService) Push ¶
func (s *IntegrationService) Push(ctx context.Context, id string, contactIDs []string, opts ...RequestOption) (*PushResult, *Response, error)
Push sends the given contacts to the provider now, rather than waiting for an event to fire.
func (*IntegrationService) ReauthOAuth ¶
func (s *IntegrationService) ReauthOAuth(ctx context.Context, id string, opts ...RequestOption) (*OAuthStartResult, *Response, error)
ReauthOAuth restarts consent for a connection whose token expired or was revoked, returning a fresh URL to send the user to.
func (*IntegrationService) ReplaceFieldMappings ¶
func (s *IntegrationService) ReplaceFieldMappings(ctx context.Context, id, object string, mappings []FieldMappingInput, opts ...RequestOption) ([]FieldMapping, *Response, error)
ReplaceFieldMappings replaces the mappings for one provider object wholesale.
func (*IntegrationService) Runs ¶
func (s *IntegrationService) Runs(ctx context.Context, id string, opts ...RequestOption) ([]SyncRun, *Response, error)
Runs returns a connection's recent sync runs.
func (*IntegrationService) StartOAuth ¶
func (s *IntegrationService) StartOAuth(ctx context.Context, provider, label string, opts ...RequestOption) (*OAuthStartResult, *Response, error)
StartOAuth begins the consent flow for an OAuth provider and returns the URL to send the user to. The label, if given, names the resulting connection.
func (*IntegrationService) Test ¶
func (s *IntegrationService) Test(ctx context.Context, id string, opts ...RequestOption) (bool, *Response, error)
Test sends a test message through the connection to confirm it works. For a notification provider this posts a real message to the configured channel.
func (*IntegrationService) UpdateConfig ¶
func (s *IntegrationService) UpdateConfig(ctx context.Context, id string, params *ConnectionConfigParams, opts ...RequestOption) (*IntegrationConnection, *Response, error)
UpdateConfig changes a connection's non-secret configuration.
func (*IntegrationService) WebhookSecret ¶
func (s *IntegrationService) WebhookSecret(ctx context.Context, id string, opts ...RequestOption) (*ConnectionWebhookSecret, *Response, error)
WebhookSecret returns the signing material an inbound provider needs. Treat the secret as a credential.
type Invitation ¶
type Invitation struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Email string `json:"email"`
Role string `json:"role"`
RoleID *string `json:"role_id,omitempty"`
Roles []MemberRole `json:"roles,omitempty"`
Permissions uint16 `json:"permissions"`
InvitedBy string `json:"invited_by"`
ExpiresAt time.Time `json:"expires_at"`
CreatedAt time.Time `json:"created_at"`
Organization *Organization `json:"organization,omitempty"`
InvitedByUser *User `json:"invited_by_user,omitempty"`
}
Invitation is a pending invitation to join an organization. The invite token is never returned in a listing; fetch it with OrganizationService.InvitationLink.
func (*Invitation) Expired ¶
func (i *Invitation) Expired() bool
Expired reports whether the invitation has lapsed.
type InvitationPreview ¶ added in v0.3.0
type InvitationPreview struct {
OrganizationName string `json:"organization_name"`
OrganizationAvatar string `json:"organization_avatar,omitempty"`
// InviterName is who sent it, when the API knows.
InviterName string `json:"inviter_name,omitempty"`
// Email is the address the invitation was issued to; only that address can
// accept it.
Email string `json:"email"`
// Roles are the roles the invitee would land in.
Roles []MemberRole `json:"roles"`
// Expired is true when the invitation has lapsed and can no longer be
// accepted.
Expired bool `json:"expired"`
}
InvitationPreview is the public view of an invitation, resolved from its token before the recipient commits to joining. It deliberately carries only what a human needs to decide: no ids, no permission bitmask, and not the token itself.
type InviteMemberParams ¶
type InviteMemberParams struct {
Email string `json:"email"`
// RoleIDs are the roles the invitee lands in; at least one is required.
RoleIDs []string `json:"role_ids,omitempty"`
// RoleID is a single-role shorthand for RoleIDs.
RoleID *string `json:"role_id,omitempty"`
}
InviteMemberParams invites someone by email into one or more roles.
type LeadSyncConnection ¶
type LeadSyncConnection struct {
Connected bool `json:"connected"`
Connection *LeadSyncConnectionSummary `json:"connection"`
}
LeadSyncConnection reports whether the workspace has a Google account connected for lead sync.
type LeadSyncConnectionSummary ¶
type LeadSyncConnectionSummary struct {
ID string `json:"id"`
ExternalAccountName string `json:"external_account_name"`
// Status is one of the Connection* constants.
Status string `json:"status"`
}
LeadSyncConnectionSummary identifies the connected Google account.
type LeadSyncCreateParams ¶
type LeadSyncCreateParams struct {
ConnectionID string `json:"connection_id"`
SheetID string `json:"sheet_id"`
SheetTitle string `json:"sheet_title,omitempty"`
TabTitle string `json:"tab_title,omitempty"`
HasHeader bool `json:"has_header"`
// ColumnMapping is validated when the source is saved, with the same
// rules as a file import: it must be non-empty and map an email column,
// and every target must be a known one. A bad mapping is a 400 here
// rather than a failed sync later.
ColumnMapping []ImportColumnMapping `json:"column_mapping"`
// Dedup is one of the ImportDedup* constants.
Dedup string `json:"dedup,omitempty"`
TargetCampaignID *string `json:"target_campaign_id,omitempty"`
CategoryIDs []string `json:"category_ids,omitempty"`
SubscribedDefault *bool `json:"subscribed_default,omitempty"`
Label string `json:"label,omitempty"`
}
LeadSyncCreateParams saves a new source. ConnectionID, SheetID and a non-empty ColumnMapping are required.
type LeadSyncResult ¶
type LeadSyncResult struct {
SourceID string `json:"source_id"`
Result *ContactImportResult `json:"result"`
}
LeadSyncResult is what a manual sync returns: the import counts plus the source they belong to.
type LeadSyncService ¶
type LeadSyncService service
LeadSyncService manages on-demand Google Sheets to contacts sync: a saved binding between a spreadsheet tab and the contact importer, re-runnable with "sync now". New rows create contacts and rows matching an existing contact by email update it.
The Google account itself is connected through the ordinary integration OAuth flow with provider ProviderGoogleSheets; see IntegrationService.StartOAuth.
Setting up a source runs in three steps: LeadSyncService.Spreadsheet to list a workbook's tabs, LeadSyncService.Preview to read the columns and get a suggested mapping, then LeadSyncService.Create to save it. Preview returns the same shape as the contact importer, so one column mapper serves both.
func (*LeadSyncService) Connection ¶
func (s *LeadSyncService) Connection(ctx context.Context, opts ...RequestOption) (*LeadSyncConnection, *Response, error)
Connection reports whether a Google account is connected for lead sync.
func (*LeadSyncService) Create ¶
func (s *LeadSyncService) Create(ctx context.Context, params *LeadSyncCreateParams, opts ...RequestOption) (*LeadSyncSource, *Response, error)
Create saves a new sync source.
func (*LeadSyncService) Delete ¶
func (s *LeadSyncService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete removes a saved sync source. The contacts it imported stay.
func (*LeadSyncService) Get ¶
func (s *LeadSyncService) Get(ctx context.Context, id string, opts ...RequestOption) (*LeadSyncSource, *Response, error)
Get retrieves a saved sync source.
func (*LeadSyncService) Preview ¶
func (s *LeadSyncService) Preview(ctx context.Context, connectionID, sheetID, tabTitle string, opts ...RequestOption) (*ContactImportPreview, *Response, error)
Preview reads the top rows of a tab and returns the same shape as ContactService.ImportPreview, including a suggested column mapping.
func (*LeadSyncService) Sources ¶
func (s *LeadSyncService) Sources(ctx context.Context, opts ...RequestOption) ([]LeadSyncSource, *Response, error)
Sources returns the workspace's saved sync sources.
func (*LeadSyncService) SourcesForCampaign ¶ added in v0.3.0
func (s *LeadSyncService) SourcesForCampaign(ctx context.Context, campaignID string, opts ...RequestOption) ([]LeadSyncSource, *Response, error)
SourcesForCampaign returns the saved sync sources that enroll their leads in the given campaign.
func (*LeadSyncService) Spreadsheet ¶
func (s *LeadSyncService) Spreadsheet(ctx context.Context, connectionID, sheetID string, opts ...RequestOption) (*Spreadsheet, *Response, error)
Spreadsheet returns a workbook's title and tabs, so a tab can be chosen before mapping columns.
func (*LeadSyncService) Sync ¶
func (s *LeadSyncService) Sync(ctx context.Context, id string, opts ...RequestOption) (*LeadSyncResult, *Response, error)
Sync runs a source now and returns the import counts. It runs in the request, so a large sheet takes a while.
func (*LeadSyncService) Update ¶
func (s *LeadSyncService) Update(ctx context.Context, id string, params *LeadSyncUpdateParams, opts ...RequestOption) (*LeadSyncSource, *Response, error)
Update edits a saved sync source.
type LeadSyncSource ¶
type LeadSyncSource struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
CreatedByUserID string `json:"created_by_user_id"`
// Provider is the source system; today always [ProviderGoogleSheets].
Provider string `json:"provider"`
// ConnectionID is the integration connection the sheet is read through.
ConnectionID string `json:"connection_id"`
SheetID string `json:"sheet_id"`
SheetTitle string `json:"sheet_title,omitempty"`
TabTitle string `json:"tab_title,omitempty"`
// A1Range narrows the read to a range within the tab.
A1Range string `json:"a1_range,omitempty"`
HasHeader bool `json:"has_header"`
// ColumnMapping and Dedup are the contact-importer settings the rows flow
// through, so a sheet sync behaves exactly like a file import.
ColumnMapping []ImportColumnMapping `json:"column_mapping"`
// Dedup is one of the ImportDedup* constants.
Dedup string `json:"dedup"`
// TargetCampaignID, when set, enrolls every new or updated lead in that
// campaign on each sync.
TargetCampaignID *string `json:"target_campaign_id,omitempty"`
CategoryIDs []string `json:"category_ids"`
SubscribedDefault bool `json:"subscribed_default"`
Label string `json:"label,omitempty"`
// Status is one of the LeadSync* constants.
Status string `json:"status"`
LastSyncedAt *time.Time `json:"last_synced_at,omitempty"`
LastResult *ContactImportResult `json:"last_result,omitempty"`
LastError string `json:"last_error,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
LeadSyncSource is a saved sheet-to-contacts binding.
type LeadSyncUpdateParams ¶
type LeadSyncUpdateParams struct {
SheetID *string `json:"sheet_id,omitempty"`
SheetTitle *string `json:"sheet_title,omitempty"`
TabTitle *string `json:"tab_title,omitempty"`
HasHeader *bool `json:"has_header,omitempty"`
// ColumnMapping, when non-nil, replaces the mapping and is validated like
// on create; an empty mapping is a 400.
ColumnMapping *[]ImportColumnMapping `json:"column_mapping,omitempty"`
Dedup *string `json:"dedup,omitempty"`
TargetCampaignID *string `json:"target_campaign_id,omitempty"`
// ClearCampaign detaches the target campaign. Use it instead of a nil
// TargetCampaignID, which means "leave unchanged".
ClearCampaign bool `json:"clear_campaign,omitempty"`
CategoryIDs *[]string `json:"category_ids,omitempty"`
SubscribedDefault *bool `json:"subscribed_default,omitempty"`
Label *string `json:"label,omitempty"`
}
LeadSyncUpdateParams edits a saved source. Nil fields are left unchanged.
type LimitRequest ¶
type LimitRequest struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
// Field names the ceiling being raised: one of the LimitField*
// constants.
Field string `json:"field"`
// CurrentEffective is what the limit was when the request was filed, so a
// reviewer sees what the asker was looking at.
CurrentEffective int `json:"current_effective"`
Requested int `json:"requested"`
Reason string `json:"reason"`
// Status is one of the LimitRequest* constants.
Status string `json:"status"`
SubmittedBy string `json:"submitted_by"`
SubmittedAt time.Time `json:"submitted_at"`
ReviewedBy *string `json:"reviewed_by,omitempty"`
ReviewedAt *time.Time `json:"reviewed_at,omitempty"`
ReviewNotes string `json:"review_notes,omitempty"`
}
LimitRequest is an ask for a higher plan ceiling, pending review.
type LimitRequestParams ¶
type LimitRequestParams struct {
Field string `json:"field"`
Requested int `json:"requested"`
Reason string `json:"reason"`
}
LimitRequestParams asks for a higher ceiling. Field is one of the LimitField* constants, Requested must exceed the current effective limit, and Reason (up to 2000 characters) is required. A mailbox request on a workspace whose allowance is unlimited is refused.
type LimitsAndCounts ¶
type LimitsAndCounts struct {
Limits *OrganizationLimits `json:"limits"`
Counts *OrganizationCounts `json:"counts"`
// Mailboxes is how many mailboxes the workspace may hold and why.
Mailboxes *MailboxAllowance `json:"mailboxes,omitempty"`
// Storage is attachment storage against its quota.
Storage *StorageUsage `json:"storage,omitempty"`
}
LimitsAndCounts pairs the enforced ceilings with current usage, plus the two meters that have no plan column of their own: the mailbox allowance and attachment storage.
type ListOptions ¶
type ListOptions struct {
// Limit is the maximum number of items per page (server-capped, typically
// at 100). Zero uses the server default.
Limit int `json:"-"`
// Cursor is the opaque pagination token from a previous page's NextCursor.
Cursor string `json:"-"`
}
ListOptions are the pagination controls common to every list endpoint. Resource-specific list parameter types embed it. They always travel in the query string, so they are never serialized into a request body even when embedded in a POST-search parameter type.
type LoginParams ¶
type LoginParams struct {
Email string `json:"email"`
Password string `json:"password"`
Turnstile string `json:"turnstile,omitempty"`
// ReferralCode is the ?ref= code a signup arrived with, so the new
// workspace is attributed to its referrer.
ReferralCode string `json:"referral_code,omitempty"`
// Invite is a team-invitation token. On a deployment that runs
// invite-only registration ([AuthConfig.InvitesRequired]) it is what
// permits the signup, and the account lands in the inviting workspace
// rather than a new one. It must resolve to a live invitation for the same
// email, or the request fails with code "invitation_invalid"; omitting it
// on a closed deployment fails with "registration_invite_only" or
// "registration_closed".
Invite string `json:"invite,omitempty"`
}
LoginParams starts a sign-in or a signup. Turnstile carries a bot-check token when the deployment requires one (AuthConfig.Captcha); the last two fields only matter to AuthService.Register.
type MCPServer ¶
type MCPServer struct {
ID string `json:"id"`
OrgID string `json:"org_id"`
Name string `json:"name"`
URL string `json:"url"`
// AuthType is "none" or "bearer". The token itself is sealed server-side
// and never returned.
AuthType string `json:"auth_type"`
Enabled bool `json:"enabled"`
// DiscoveredTools is what the server advertised on the last refresh.
DiscoveredTools []MCPTool `json:"discovered_tools"`
// LastError is why the most recent refresh failed, when it did.
LastError string `json:"last_error,omitempty"`
CreatedBy *string `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
MCPServer is an external MCP server whose tools the assistant may call.
type MCPServerParams ¶
type MCPServerParams struct {
Name string `json:"name"`
URL string `json:"url"`
// AuthType is "none" or "bearer".
AuthType string `json:"auth_type,omitempty"`
// Token is the bearer credential, sealed server-side on receipt.
Token string `json:"token,omitempty"`
}
MCPServerParams connects an MCP server.
type MCPServerUpdateParams ¶
type MCPServerUpdateParams struct {
Name *string `json:"name,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
// Token replaces the stored credential.
Token *string `json:"token,omitempty"`
}
MCPServerUpdateParams updates a connected server. Nil fields are unchanged.
type MCPTool ¶
type MCPTool struct {
Name string `json:"name"`
Description string `json:"description"`
// InputSchema is the tool's JSON Schema.
InputSchema json.RawMessage `json:"input_schema,omitempty"`
}
MCPTool is one tool discovered on a connected MCP server.
type MailboxAllowance ¶ added in v0.3.0
type MailboxAllowance struct {
// Used is the number of mailboxes connected right now.
Used int `json:"used"`
// Allowance is the cap; nil means unlimited.
Allowance *int `json:"allowance"`
// Remaining is Allowance minus Used, never negative; nil when unlimited.
Remaining *int `json:"remaining"`
// Basis is one of the MailboxAllowance* constants.
Basis string `json:"basis"`
// SendsPerMailbox is the fair-use divisor.
SendsPerMailbox int `json:"sends_per_mailbox"`
// PlanDailySends is the plan's daily send cap when it has one.
PlanDailySends *int `json:"plan_daily_sends,omitempty"`
PlanName string `json:"plan_name,omitempty"`
// Paid is false for a free workspace, whose path to more mailboxes is a
// plan rather than a limit-increase request.
Paid bool `json:"paid"`
// PendingRequest is the open limit-increase request for mailboxes (a
// [LimitRequest] on the "max_email_accounts" field), if any. File one with
// [OrganizationService.RequestLimitIncrease].
PendingRequest *LimitRequest `json:"pending_request,omitempty"`
}
MailboxAllowance is how many mailboxes a workspace holds, how many it may hold, and why. Mailboxes are unlimited on every paid plan in principle; the fair-use allowance is one mailbox per daily send the plan includes, which is far more than safe sending ever needs. Nothing is ever removed for being over the allowance: a workspace that moves to a smaller plan keeps every mailbox and simply cannot add more.
func (*MailboxAllowance) CanAdd ¶ added in v0.3.0
func (a *MailboxAllowance) CanAdd(n int) bool
CanAdd reports whether n more mailboxes fit.
func (*MailboxAllowance) Unlimited ¶ added in v0.3.0
func (a *MailboxAllowance) Unlimited() bool
Unlimited reports whether the workspace may connect any number of mailboxes.
type MailboxBulkResult ¶ added in v0.3.0
type MailboxBulkResult struct {
Data []MailboxBulkRow `json:"data"`
Summary MailboxBulkSummary `json:"summary"`
// Allowance is the workspace's mailbox allowance after the batch, so a
// caller can tell how many more rows will fit without another call.
Allowance *MailboxAllowance `json:"allowance,omitempty"`
}
MailboxBulkResult is the per-row answer to a bulk connect.
type MailboxBulkRow ¶ added in v0.3.0
type MailboxBulkRow struct {
// Row is the zero-based index of the row in the request, so failed lines
// can be handed back to whoever supplied them.
Row int `json:"row"`
Email string `json:"email"`
// Status is [MailboxBulkConnected], [MailboxBulkSkipped] or
// [MailboxBulkFailed].
Status string `json:"status"`
// Code is the stable error code for a skipped or failed row:
// "already_connected" for a skip, [ErrCodeMailboxAllowanceReached] for a
// row past the allowance, otherwise the code the single connect would have
// returned.
Code string `json:"code,omitempty"`
Message string `json:"message,omitempty"`
// ID is the new mailbox id for a connected row.
ID *string `json:"id,omitempty"`
}
MailboxBulkRow is one row's answer from a bulk connect.
type MailboxBulkSummary ¶ added in v0.3.0
type MailboxBulkSummary struct {
Total int `json:"total"`
Connected int `json:"connected"`
Skipped int `json:"skipped"`
Failed int `json:"failed"`
}
MailboxBulkSummary counts a bulk connect's rows by outcome.
type MailboxCredentials ¶
type MailboxCredentials struct {
Username string `json:"username"`
Password string `json:"password"`
Host string `json:"host"`
// Port is any port from 1 to 65535.
Port int `json:"port"`
// Security is [MailSecurityTLS] or [MailSecurityStartTLS]. Leave it empty
// to let the port decide (tls for SMTP 465 and IMAP 993, starttls for SMTP
// 587 and IMAP 143); set it for anything non-standard, such as a
// submission relay on 2525. A server expecting STARTTLS looks unreachable
// to a client attempting implicit TLS, and vice versa.
Security string `json:"security,omitempty"`
}
MailboxCredentials are the host, port and login for one leg of an SMTP/IMAP connection.
type MailboxSync ¶ added in v0.3.0
type MailboxSync struct {
// State is nil until the worker has reported once.
State *MailboxSyncState `json:"state"`
Policy MailboxSyncPolicy `json:"policy"`
}
MailboxSync is a mailbox's sync progress together with the budget it runs under.
type MailboxSyncCursor ¶ added in v0.3.0
type MailboxSyncCursor struct {
// PageToken is Gmail's messages.list continuation.
PageToken string `json:"page_token,omitempty"`
// Folders is the per-folder position for IMAP and Microsoft Graph.
Folders map[string]MailboxSyncFolderCursor `json:"folders,omitempty"`
}
MailboxSyncCursor is the resumable position of a mailbox's backfill.
type MailboxSyncFolderCursor ¶ added in v0.3.0
type MailboxSyncFolderCursor struct {
// Next is an opaque continuation (Microsoft Graph nextLink).
Next string `json:"next,omitempty"`
// UID is the lowest IMAP UID already imported; the walk continues below it.
UID uint32 `json:"uid,omitempty"`
// Done marks the folder exhausted for this window.
Done bool `json:"done,omitempty"`
}
MailboxSyncFolderCursor is the resumable position inside one folder of a backfill. It is opaque operational detail, surfaced for diagnostics only.
type MailboxSyncPolicy ¶ added in v0.3.0
type MailboxSyncPolicy struct {
// BackfillDays is how far back the initial import reaches (90 by default).
BackfillDays int `json:"backfill_days"`
// BackfillMessages caps how many messages the initial import stores
// (5000 by default).
BackfillMessages int `json:"backfill_messages"`
// DailyMessages caps new (live) messages stored per UTC day. Replies to
// the mailbox's own sends have a separate budget of the same size.
DailyMessages int `json:"daily_messages"`
// OrgDailyMessages caps new plus backfilled messages stored across the
// whole organization per UTC day.
OrgDailyMessages int `json:"org_daily_messages"`
}
MailboxSyncPolicy is the fair-use budget a mailbox syncs under. Mail over a budget is not dropped: it waits on the server with the cursor held and comes in when the window rolls.
type MailboxSyncState ¶ added in v0.3.0
type MailboxSyncState struct {
// BackfillStatus is [SyncBackfillPending], [SyncBackfillRunning] or
// [SyncBackfillComplete].
BackfillStatus string `json:"backfill_status"`
BackfillCursor MailboxSyncCursor `json:"backfill_cursor"`
// BackfillSynced counts messages the import has stored so far.
BackfillSynced int `json:"backfill_synced"`
// BackfillSince is the cutoff the running import uses, fixed at start so
// a later settings change does not move the goalposts mid-walk.
BackfillSince *time.Time `json:"backfill_since,omitempty"`
BackfillStartedAt *time.Time `json:"backfill_started_at,omitempty"`
BackfillCompletedAt *time.Time `json:"backfill_completed_at,omitempty"`
// ThrottledUntil is set while fair use is deferring live mail; nil when
// the mailbox is within budget.
ThrottledUntil *time.Time `json:"throttled_until,omitempty"`
// ThrottleReason names the exhausted budget, one of the SyncThrottle*
// constants.
ThrottleReason string `json:"throttle_reason,omitempty"`
// Deferred counts live messages currently waiting on budget: seen on the
// server but not yet stored. It drops back to zero once they are admitted.
Deferred int `json:"deferred"`
LastSyncedAt *time.Time `json:"last_synced_at,omitempty"`
}
MailboxSyncState is what the platform knows about a mailbox's sync: backfill progress, whether fair use is holding it, and when it last ran.
type Meeting ¶
type Meeting struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
// Source is the scheduling provider, or "manual" for one logged by hand.
Source string `json:"source"`
// ExternalEventID is the provider's identifier for the booking.
ExternalEventID string `json:"external_event_id,omitempty"`
// Status is one of the Meeting* constants.
Status string `json:"status"`
InviteeEmail string `json:"invitee_email"`
InviteeName string `json:"invitee_name"`
EventName string `json:"event_name"`
EventType string `json:"event_type,omitempty"`
ScheduledFor *time.Time `json:"scheduled_for,omitempty"`
EndTime *time.Time `json:"end_time,omitempty"`
JoinURL string `json:"join_url,omitempty"`
Location string `json:"location,omitempty"`
CancelURL string `json:"cancel_url,omitempty"`
RescheduleURL string `json:"reschedule_url,omitempty"`
// CanceledReason is set once the booking is canceled.
CanceledReason string `json:"canceled_reason,omitempty"`
ContactID *string `json:"contact_id,omitempty"`
CampaignID *string `json:"campaign_id,omitempty"`
// ContactName is joined in for display.
ContactName string `json:"contact_name,omitempty"`
// RawPayload is the provider's original webhook body.
RawPayload json.RawMessage `json:"raw_payload,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Meeting is one booked call.
type MeetingCreateParams ¶
type MeetingCreateParams struct {
Title string `json:"title,omitempty"`
InviteeName string `json:"invitee_name,omitempty"`
InviteeEmail string `json:"invitee_email"`
// ScheduledFor is an RFC 3339 timestamp and is required.
ScheduledFor string `json:"scheduled_for,omitempty"`
DurationMinutes int `json:"duration_minutes,omitempty"`
Location string `json:"location,omitempty"`
JoinURL string `json:"join_url,omitempty"`
ContactID string `json:"contact_id,omitempty"`
}
MeetingCreateParams logs a meeting that was booked outside a connected provider. It is matched to a contact by InviteeEmail unless ContactID says otherwise. At least one of InviteeName and InviteeEmail is required, as is a parseable ScheduledFor; Title defaults to "Call".
A meeting logged this way is recorded with source "manual" and does not fire the "meeting booked" automations a provider booking would, so logging your own call never alerts you about it.
type MeetingListParams ¶
type MeetingListParams struct {
ListOptions
// Timeframe is [MeetingsUpcoming] or [MeetingsPast]. Empty returns both.
Timeframe string
// Status is one of the Meeting* constants.
Status string
// Query is a free-text search over the invitee and the event name.
Query string
}
MeetingListParams filters and paginates the meetings list.
type MeetingService ¶
type MeetingService service
MeetingService lists meetings booked through a connected scheduling provider such as Calendly or Cal.com, and lets one be logged by hand.
func (*MeetingService) Create ¶
func (s *MeetingService) Create(ctx context.Context, params *MeetingCreateParams, opts ...RequestOption) (*Meeting, *Response, error)
Create logs a meeting booked outside a connected provider.
func (*MeetingService) Delete ¶
func (s *MeetingService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete removes a meeting record.
func (*MeetingService) List ¶
func (s *MeetingService) List(ctx context.Context, params *MeetingListParams, opts ...RequestOption) (*Page[Meeting], error)
List returns a page of booked meetings.
func (*MeetingService) Summary ¶
func (s *MeetingService) Summary(ctx context.Context, opts ...RequestOption) (*MeetingsSummary, *Response, error)
Summary returns the meeting counters.
type MeetingsSummary ¶
type MeetingsSummary struct {
Upcoming int `json:"upcoming"`
Today int `json:"today"`
Total int `json:"total"`
Canceled int `json:"canceled"`
}
MeetingsSummary counts booked meetings for a header row.
type Member ¶
type Member struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
// Role is the built-in role name, one of the Role* constants. Owner is a
// membership flag rather than a role row.
Role string `json:"role"`
// RoleID is the member's first assigned role; Roles is the full set.
RoleID *string `json:"role_id,omitempty"`
Roles []MemberRole `json:"roles,omitempty"`
// Permissions is the effective grant across every assigned role. Test it
// with [Member.Can].
Permissions uint16 `json:"permissions"`
InvitedBy *string `json:"invited_by,omitempty"`
InvitedAt time.Time `json:"invited_at"`
AcceptedAt *time.Time `json:"accepted_at,omitempty"`
User *User `json:"user,omitempty"`
Organization *Organization `json:"organization,omitempty"`
// Email and Name are flattened from the joined user for convenience.
Email string `json:"email"`
Name string `json:"name"`
}
Member is a user's membership in an organization.
type MemberRole ¶
type MemberRole struct {
ID string `json:"id"`
Name string `json:"name"`
Color string `json:"color"`
}
MemberRole is a lightweight role reference for rendering the roles a member holds, without the permission payload.
type MessageParams ¶
type MessageParams struct {
// MessageID deduplicates a retried send. Leave it empty and the server
// generates one.
MessageID string `json:"message_id,omitempty"`
Text string `json:"text"`
// Page and Resource tell the assistant what the user is looking at, so
// references like "this campaign" resolve.
Page string `json:"page,omitempty"`
Resource string `json:"resource,omitempty"`
}
MessageParams sends a message to the assistant.
type MetaService ¶
type MetaService service
MetaService reads the small, cross-cutting endpoints: who the current credential is, the plan catalog, and the timezone list.
func (*MetaService) GatewayTicket ¶
func (s *MetaService) GatewayTicket(ctx context.Context, opts ...RequestOption) (*GatewayTicket, *Response, error)
GatewayTicket mints a single-use websocket ticket for the current session. This route is session-only.
func (*MetaService) Identity ¶
func (s *MetaService) Identity(ctx context.Context, opts ...RequestOption) (*Identity, *Response, error)
Identity returns who the current credential is and which workspace it acts on. Any valid credential can call it, whatever its scopes.
func (*MetaService) Plans ¶
func (s *MetaService) Plans(ctx context.Context, opts ...RequestOption) ([]Plan, *Response, error)
Plans returns the public plan catalog. On a deployment without a billing provider (AuthConfig.BillingEnabled false) the route is absent.
func (*MetaService) Realtime ¶
func (s *MetaService) Realtime(ctx context.Context, opts ...RequestOption) (*RealtimeInfo, *Response, error)
Realtime returns the gateway's connection details. This route is session-only. For a programmatic gateway connection, authenticate with an API key holding PermRealtimeSubscribe; see the gateway subpackage.
func (*MetaService) Timezones ¶
func (s *MetaService) Timezones(ctx context.Context, opts ...RequestOption) ([]Timezone, *Response, error)
Timezones returns the timezones a campaign schedule or mailbox can use.
type MiniCampaign ¶
MiniCampaign is a campaign reference embedded in another resource.
type MiniCategory ¶
type MiniCategory struct {
ID string `json:"id"`
Title string `json:"title"`
Color string `json:"color"`
}
MiniCategory is a contact category (also surfaced as a conversation label in the unified inbox) embedded in another resource.
type NodePosition ¶
NodePosition is one node's coordinates on the builder canvas.
type Notification ¶
type Notification struct {
ID string `json:"id"`
UserID string `json:"user_id"`
OrganizationID *string `json:"organization_id,omitempty"`
// Category is one of the Notif* constants.
Category string `json:"category"`
Title string `json:"title"`
Body string `json:"body,omitempty"`
Link string `json:"link,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
// ReadAt is nil while the notification is unread.
ReadAt *time.Time `json:"read_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
Notification is one entry in the in-app feed.
type NotificationEmailDelivery ¶ added in v0.3.0
type NotificationEmailDelivery struct {
MinMinutes int `json:"min_minutes"`
MaxMinutes int `json:"max_minutes"`
// DailyCap is the most notification emails one account receives a day.
DailyCap int `json:"daily_cap"`
}
NotificationEmailDelivery is the deployment's bounds for the email channel, so a digest-window control renders the right range.
type NotificationFeed ¶
type NotificationFeed struct {
Notifications []Notification `json:"notifications"`
Unread int `json:"unread"`
}
NotificationFeed is a page of the in-app feed plus the unread count.
type NotificationPreferences ¶
type NotificationPreferences struct {
InboundReply CategoryPref `json:"inbound_reply"`
InboundOOO CategoryPref `json:"inbound_out_of_office"`
HealthBounce CategoryPref `json:"health_bounce"`
HealthComplaint CategoryPref `json:"health_complaint"`
WorkerDowntime CategoryPref `json:"health_worker_downtime"`
SecuritySignIn CategoryPref `json:"security_new_signin"`
BillingAlert CategoryPref `json:"billing_alert"`
TeamActivity CategoryPref `json:"team_activity"`
// CampaignPaused and DomainAuth default to on with email: both mean the
// platform will (or did) stop sending, so they must reach someone who can
// act.
CampaignPaused CategoryPref `json:"campaign_paused"`
DomainAuth CategoryPref `json:"health_domain_auth"`
// EmailDigestMinutes bundles pending notification emails into one send.
// It must fall within [NotificationEmailDelivery.MinMinutes] and
// [NotificationEmailDelivery.MaxMinutes]; zero on an update means the
// server default. Security sign-in alerts always go out immediately
// regardless.
EmailDigestMinutes int `json:"email_digest_minutes"`
}
NotificationPreferences is the caller's full notification configuration. It is always returned fully populated.
type NotificationPreferencesResult ¶
type NotificationPreferencesResult struct {
Preferences NotificationPreferences `json:"preferences"`
EmailDelivery *NotificationEmailDelivery `json:"email_delivery,omitempty"`
}
NotificationPreferencesResult is the preferences plus how email delivery is configured on this deployment.
type OAuth2Config ¶
type OAuth2Config struct {
// ClientID is the application's public client identifier.
ClientID string
// ClientSecret is the confidential client secret. Leave empty for public
// clients that rely solely on PKCE.
ClientSecret string
// RedirectURL must exactly match one of the application's registered URIs.
RedirectURL string
// Scopes are the permission keys to request.
Scopes []string
// Endpoint overrides the authorization server URLs. Zero uses
// [DefaultEndpoint].
Endpoint OAuth2Endpoint
// HTTPClient is used for token requests. Nil uses a sensible default.
HTTPClient *http.Client
}
OAuth2Config configures the OAuth 2.1 authorization-code flow (with optional PKCE) for an application acting on behalf of a user.
A typical web flow:
cfg := &warmbly.OAuth2Config{
ClientID: "...",
ClientSecret: "...",
RedirectURL: "https://app.example.com/callback",
Scopes: []string{"campaigns:read", "contacts:read"},
}
verifier := warmbly.GenerateVerifier()
url := cfg.AuthCodeURL(state, warmbly.S256ChallengeOption(verifier))
// ... redirect the user, receive ?code=... on the callback ...
tok, err := cfg.Exchange(ctx, code, warmbly.VerifierOption(verifier))
client, err := cfg.NewClient(ctx, tok)
func (*OAuth2Config) AuthCodeURL ¶
func (c *OAuth2Config) AuthCodeURL(state string, opts ...AuthCodeOption) string
AuthCodeURL builds the URL to which the user should be redirected to grant authorization. state is an opaque, unguessable value echoed back to the redirect URI; verify it to defend against CSRF. Pass S256ChallengeOption to use PKCE (strongly recommended, and required for public clients).
func (*OAuth2Config) Exchange ¶
func (c *OAuth2Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error)
Exchange trades an authorization code for a token. When PKCE was used, pass VerifierOption with the same verifier supplied to S256ChallengeOption.
func (*OAuth2Config) NewClient ¶
NewClient builds a *Client authenticated with a refreshing token source seeded from t.
func (*OAuth2Config) Revoke ¶
func (c *OAuth2Config) Revoke(ctx context.Context, token string) error
Revoke revokes an access or refresh token.
func (*OAuth2Config) TokenSource ¶
func (c *OAuth2Config) TokenSource(ctx context.Context, t *Token) TokenSource
TokenSource returns a TokenSource that starts from t and transparently refreshes the access token using its refresh token as it expires. It is safe for concurrent use.
type OAuth2Endpoint ¶
type OAuth2Endpoint struct {
// AuthURL is the user-facing authorization (consent) URL.
AuthURL string
// TokenURL is the token endpoint (code exchange, refresh, client creds).
TokenURL string
// RevokeURL is the token revocation endpoint.
RevokeURL string
}
OAuth2Endpoint holds the URLs of the Warmbly authorization server. The zero value falls back to DefaultEndpoint.
type OAuth2Error ¶
type OAuth2Error struct {
StatusCode int `json:"-"`
Code string `json:"error"`
Description string `json:"error_description"`
URI string `json:"error_uri"`
Message string `json:"message"`
RequestID string `json:"request_id"`
// Body is the raw error-response body for diagnostics. It is only populated
// for non-2xx responses (never a successful token payload), so it does not
// carry issued credentials.
Body []byte `json:"-"`
}
OAuth2Error is returned when the token or revocation endpoint responds with an error. It carries both the RFC 6749 fields (Code/Description) and the Warmbly error envelope fields (Message/RequestID).
func (*OAuth2Error) Error ¶
func (e *OAuth2Error) Error() string
type OAuthApp ¶
type OAuthApp struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
CreatedBy string `json:"created_by"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
LogoURL string `json:"logo_url,omitempty"`
WebsiteURL string `json:"website_url,omitempty"`
// ClientID is the public client identifier.
ClientID string `json:"client_id"`
// RedirectURIs are the exact URIs the authorization code may be returned
// to. They are matched exactly, not by prefix.
RedirectURIs []string `json:"redirect_uris"`
// Scopes is the permission bitmask the app may request, built from the
// Perm* constants.
Scopes uint64 `json:"scopes"`
// AllowedWebhookDomains constrains the host of any webhook endpoint the
// app registers. A leading dot matches subdomains; without one the match
// is exact. Empty means the app cannot register webhooks at all.
AllowedWebhookDomains []string `json:"allowed_webhook_domains,omitempty"`
// WebhookURL turns on the app-level subscription: every workspace that
// authorizes the app delivers to this URL, scoped to what that workspace
// granted. Its host must fall inside AllowedWebhookDomains.
WebhookURL string `json:"webhook_url,omitempty"`
// WebhookEvents narrows that subscription. Empty means every non-firehose
// event the grant's scopes allow.
WebhookEvents []string `json:"webhook_events,omitempty"`
// Status is [OAuthAppActive] or [OAuthAppInactive].
Status string `json:"status"`
// IsPublic marks a client that authenticates with PKCE and no secret, such
// as a native app or an MCP client. PKCE is mandatory for these.
IsPublic bool `json:"is_public"`
// DynamicallyRegistered is true for clients that self-registered through
// the RFC 7591 endpoint.
DynamicallyRegistered bool `json:"dynamically_registered"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
OAuthApp is a registered OAuth 2.1 application. The client secret is never included here; it is returned once by OAuthAppService.Create and OAuthAppService.RotateSecret.
type OAuthAppParams ¶
type OAuthAppParams struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
LogoURL string `json:"logo_url,omitempty"`
WebsiteURL string `json:"website_url,omitempty"`
RedirectURIs []string `json:"redirect_uris"`
// Scopes is the permission bitmask, built from the Perm* constants.
Scopes uint64 `json:"scopes"`
AllowedWebhookDomains []string `json:"allowed_webhook_domains,omitempty"`
WebhookURL string `json:"webhook_url,omitempty"`
WebhookEvents []string `json:"webhook_events,omitempty"`
}
OAuthAppParams registers or replaces an OAuth application. The API rewrites the application from what you send rather than merging, so send the complete desired state on update.
type OAuthAppService ¶
type OAuthAppService service
OAuthAppService registers and manages OAuth 2.1 applications: the client credentials, redirect URIs and scopes an integration uses to act on behalf of a Warmbly user, plus the app-level webhook subscription that comes with them.
This service administers applications. To act as an OAuth client — build an authorization URL, exchange a code, refresh a token — use OAuth2Config and ClientCredentialsConfig instead.
func (*OAuthAppService) Authorize ¶
func (s *OAuthAppService) Authorize(ctx context.Context, params *AuthorizeParams, opts ...RequestOption) (string, *Response, error)
Authorize approves a consent request and returns the URL the browser should be sent to, carrying the authorization code back to the application.
func (*OAuthAppService) AuthorizeDetails ¶
func (s *OAuthAppService) AuthorizeDetails(ctx context.Context, query url.Values, opts ...RequestOption) (*ConsentInfo, *Response, error)
AuthorizeDetails resolves an incoming authorization request into what a consent screen should show. Pass the query parameters the application sent the user with.
func (*OAuthAppService) AuthorizedApps ¶
func (s *OAuthAppService) AuthorizedApps(ctx context.Context, opts ...RequestOption) ([]AuthorizedApp, *Response, error)
AuthorizedApps returns the applications the caller has granted access to the current workspace.
func (*OAuthAppService) Create ¶
func (s *OAuthAppService) Create(ctx context.Context, params *OAuthAppParams, opts ...RequestOption) (*OAuthAppWithSecret, *Response, error)
Create registers a new OAuth application. The returned OAuthAppWithSecret is the only time the client secret is available.
func (*OAuthAppService) Delete ¶
func (s *OAuthAppService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete permanently removes an OAuth application, revoking every token issued under it.
func (*OAuthAppService) Get ¶
func (s *OAuthAppService) Get(ctx context.Context, id string, opts ...RequestOption) (*OAuthApp, *Response, error)
Get retrieves a single OAuth application.
func (*OAuthAppService) List ¶
func (s *OAuthAppService) List(ctx context.Context, opts ...RequestOption) ([]OAuthApp, *Response, error)
List returns the workspace's registered OAuth applications.
func (*OAuthAppService) RegisterDynamicClient ¶
func (s *OAuthAppService) RegisterDynamicClient(ctx context.Context, params *DynamicClientParams, opts ...RequestOption) (*DynamicClient, *Response, error)
RegisterDynamicClient self-registers an OAuth client. The endpoint is open and unauthenticated but per-IP rate limited, and registration alone grants no access — a human still has to consent.
func (*OAuthAppService) RevokeAuthorizedApp ¶
func (s *OAuthAppService) RevokeAuthorizedApp(ctx context.Context, applicationID string, opts ...RequestOption) (*Response, error)
RevokeAuthorizedApp withdraws the caller's grant to an application and revokes its tokens.
func (*OAuthAppService) RotateSecret ¶
func (s *OAuthAppService) RotateSecret(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
RotateSecret issues a new client secret and returns it. The previous secret stops working immediately, so deploy the new one before rotating.
func (*OAuthAppService) RotateWebhookSecret ¶
func (s *OAuthAppService) RotateWebhookSecret(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
RotateWebhookSecret issues a new app-webhook signing secret and returns it. The previous secret stops verifying immediately.
func (*OAuthAppService) Update ¶
func (s *OAuthAppService) Update(ctx context.Context, id string, params *OAuthAppParams, opts ...RequestOption) (*OAuthApp, *Response, error)
Update replaces an OAuth application's registration. See OAuthAppParams.
func (*OAuthAppService) UploadLogo ¶
func (s *OAuthAppService) UploadLogo(ctx context.Context, file *FileUpload, opts ...RequestOption) (string, *Response, error)
UploadLogo stores an app logo (PNG or JPEG, up to 2 MB) and returns its URL, which you then pass in OAuthAppParams.LogoURL. It is a separate call so a logo can be uploaded during registration, before the app has an id.
func (*OAuthAppService) WebhookDeliveries ¶
func (s *OAuthAppService) WebhookDeliveries(ctx context.Context, id string, params *WebhookDeliveryListParams, opts ...RequestOption) (*Page[WebhookDelivery], error)
WebhookDeliveries returns a page of the app's delivery log, across every workspace that authorized it.
func (*OAuthAppService) WebhookEndpoints ¶
func (s *OAuthAppService) WebhookEndpoints(ctx context.Context, id string, opts ...RequestOption) ([]Webhook, *Response, error)
WebhookEndpoints returns the per-workspace endpoints materialized from the app-level subscription, one for each workspace that authorized the app.
func (*OAuthAppService) WebhookSecret ¶
func (s *OAuthAppService) WebhookSecret(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
WebhookSecret returns the signing secret for the app-level webhook subscription. Verify deliveries with it exactly as for an ordinary endpoint; see VerifyWebhookSignature.
type OAuthAppWithSecret ¶
type OAuthAppWithSecret struct {
OAuthApp
// ClientSecret cannot be retrieved again. Store it securely.
ClientSecret string `json:"client_secret,omitempty"`
}
OAuthAppWithSecret is an OAuthApp together with its plaintext client secret, returned only at creation.
type OAuthStartResult ¶
OAuthStartResult is the provider consent URL plus the state value that ties the round trip together.
type OnboardingParams ¶
type OnboardingParams struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
// ReferralSource is how they found Warmbly.
ReferralSource string `json:"referral_source,omitempty"`
Role string `json:"role,omitempty"`
TeamSize string `json:"team_size,omitempty"`
}
OnboardingParams completes the first-run questions. FirstName and LastName are required; the rest are validated against fixed sets, so an unexpected value is rejected rather than stored.
type Option ¶
Option configures a Client. Options are applied in order by New.
func WithAPIKey ¶
WithAPIKey authenticates the client with a Warmbly API key (prefixed "wmbly_"). This is the recommended scheme for server-to-server access.
func WithAccessToken ¶
WithAccessToken authenticates the client with a static OAuth 2.1 access token (prefixed "wmblyo_"). Prefer WithTokenSource when you have a refresh token and want transparent renewal.
func WithAuthenticator ¶
func WithAuthenticator(a Authenticator) Option
WithAuthenticator sets a custom Authenticator, for advanced scenarios not covered by the built-in schemes.
func WithBaseURL ¶
WithBaseURL overrides the API base URL (default https://api.warmbly.com/v1). Useful for targeting a self-hosted instance or a staging environment. The URL should include the version path segment.
func WithHTTPClient ¶
WithHTTPClient sets the underlying *http.Client. Use this to customize transport, proxies, TLS or timeouts. The client's Timeout, if any, applies to each individual request.
func WithHeader ¶
WithHeader sets a default header sent on every request. It may be called multiple times to set several headers.
func WithMaxRetries ¶
WithMaxRetries sets how many times the client retries a request that fails with a 429 or 5xx response. Retries use exponential backoff with jitter and honor any Retry-After header. The default is 2; set 0 to disable retries.
func WithRetryWaitBounds ¶
WithRetryWaitBounds sets the minimum and maximum backoff between retries.
func WithTokenSource ¶
func WithTokenSource(src TokenSource) Option
WithTokenSource authenticates the client with a TokenSource, refreshing the access token transparently as it expires.
func WithUserAgent ¶
WithUserAgent appends a product token to the default User-Agent, so requests from your application are identifiable in Warmbly's logs.
type OrgArchiveInfo ¶ added in v0.3.0
type OrgArchiveInfo struct {
FormatVersion int `json:"format_version"`
SourceInstance string `json:"source_instance"`
SourceAppVersion string `json:"source_app_version"`
OrganizationID string `json:"organization_id"`
OrganizationName string `json:"organization_name"`
ExportedAt time.Time `json:"exported_at"`
Groups []string `json:"groups"`
HasSecrets bool `json:"has_secrets"`
RowCounts map[string]int64 `json:"row_counts"`
BlobCount int `json:"blob_count"`
Members []OrgArchiveUser `json:"members"`
}
OrgArchiveInfo is the safe-to-show summary of an archive's manifest.
type OrgArchiveUser ¶ added in v0.3.0
type OrgArchiveUser struct {
ID string `json:"id"`
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Role string `json:"role"`
IsOwner bool `json:"is_owner"`
}
OrgArchiveUser is a member carried by an archive. The importer matches these to destination accounts by email; there is no password material, so an archive can never mint a login.
type OrgDataGroupInfo ¶ added in v0.3.0
type OrgDataGroupInfo struct {
// Key is one of the OrgDataGroup* constants.
Key string `json:"key"`
Label string `json:"label"`
Description string `json:"description"`
// Required groups cannot be switched off.
Required bool `json:"required"`
// Heavy marks the groups that dominate archive size on a busy workspace.
Heavy bool `json:"heavy"`
// Requires names the groups this one cannot travel without. Selecting a
// group selects these too, on the server as well.
Requires []string `json:"requires,omitempty"`
}
OrgDataGroupInfo describes one data group from the server's own catalog, so a picker renders from it rather than from a copy that drifts.
type OrgExportJob ¶ added in v0.3.0
type OrgExportJob struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
RequestedBy *string `json:"requested_by,omitempty"`
// Status is one of the OrgTransfer* constants.
Status string `json:"status"`
// Groups are the data groups the archive carries; IncludeSecrets whether
// credentials were re-sealed into it.
Groups []string `json:"groups"`
IncludeSecrets bool `json:"include_secrets"`
FormatVersion int `json:"format_version"`
ProgressPercent int `json:"progress_percent"`
ProgressStage string `json:"progress_stage"`
// ArchiveBytes and ArchiveSHA256 describe the finished file; RowCounts is
// per-table.
ArchiveBytes *int64 `json:"archive_bytes,omitempty"`
ArchiveSHA256 *string `json:"archive_sha256,omitempty"`
RowCounts map[string]int64 `json:"row_counts"`
ErrorMessage *string `json:"error_message,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
// ExpiresAt is when the archive is deleted from storage.
ExpiresAt *time.Time `json:"expires_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
OrgExportJob is one archive build. Poll OrganizationService.Export until OrgExportJob.Terminal; a completed job can be downloaded until ExpiresAt.
func (*OrgExportJob) Terminal ¶ added in v0.3.0
func (j *OrgExportJob) Terminal() bool
Terminal reports whether the job has stopped moving.
func (*OrgExportJob) TotalRows ¶ added in v0.3.0
func (j *OrgExportJob) TotalRows() int64
TotalRows sums every table's row count.
type OrgExportParams ¶ added in v0.3.0
type OrgExportParams struct {
// Groups to include (OrgDataGroup* constants). Empty means every group;
// [OrgDataGroupCore] is always included, and a group's requirements are
// pulled in with it.
Groups []string `json:"groups,omitempty"`
// IncludeSecrets re-seals mailbox and integration credentials into the
// archive under Passphrase, so the destination brings mailboxes back
// without everyone reconnecting. It requires Passphrase.
IncludeSecrets bool `json:"include_secrets,omitempty"`
// Passphrase protects the secrets bundle; at least
// [OrgTransferCatalog.MinPassphrase] characters. It is never stored: lose
// it and the credentials in that archive are unrecoverable.
Passphrase string `json:"passphrase,omitempty"`
}
OrgExportParams starts an archive build.
type OrgImportJob ¶ added in v0.3.0
type OrgImportJob struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
RequestedBy *string `json:"requested_by,omitempty"`
// Status is one of the OrgTransfer* constants.
Status string `json:"status"`
ArchiveBytes *int64 `json:"archive_bytes,omitempty"`
ArchiveSHA256 *string `json:"archive_sha256,omitempty"`
// SourceManifest summarizes the archive that was applied.
SourceManifest *OrgArchiveInfo `json:"source_manifest,omitempty"`
Groups []string `json:"groups"`
// ConflictStrategy is [OrgImportSkip] or [OrgImportOverwrite].
ConflictStrategy string `json:"conflict_strategy"`
ProgressPercent int `json:"progress_percent"`
ProgressStage string `json:"progress_stage"`
RowCounts map[string]int64 `json:"row_counts"`
Warnings []string `json:"warnings"`
ErrorMessage *string `json:"error_message,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
OrgImportJob is one archive application. Poll OrganizationService.Import until OrgImportJob.Terminal.
func (*OrgImportJob) Terminal ¶ added in v0.3.0
func (j *OrgImportJob) Terminal() bool
Terminal reports whether the job has stopped moving.
type OrgImportParams ¶ added in v0.3.0
type OrgImportParams struct {
// Groups to apply. Empty means every group present in the archive.
Groups []string `json:"groups,omitempty"`
// ConflictStrategy is [OrgImportSkip] (the default) or
// [OrgImportOverwrite].
ConflictStrategy string `json:"conflict_strategy,omitempty"`
// Passphrase unseals the archive's secrets bundle. Omit it and the import
// still runs; mailboxes and integrations just arrive needing a reconnect.
Passphrase string `json:"-"`
}
OrgImportParams applies an archive.
type OrgImportPreflight ¶ added in v0.3.0
type OrgImportPreflight struct {
Archive *OrgArchiveInfo `json:"archive"`
// SecretsUnsealed reports whether the passphrase actually opened the
// secrets bundle, so mailboxes will reconnect on their own.
SecretsUnsealed bool `json:"secrets_unsealed"`
// Conflicts is the per-table count of rows already present here.
Conflicts map[string]int64 `json:"conflicts"`
// UnknownMembers have no account on this instance; they are imported as
// pending invitations.
UnknownMembers []OrgArchiveUser `json:"unknown_members"`
// SkippedTables are in the archive but unknown here, usually because it
// came from a newer release.
SkippedTables []string `json:"skipped_tables"`
Warnings []string `json:"warnings"`
}
OrgImportPreflight is what an archive would do, without writing anything.
type OrgRisk ¶ added in v0.3.0
type OrgRisk struct {
// State is one of the OrgRisk* constants.
State string `json:"state"`
// Restricted is true for restricted and suspended; volume is reduced.
Restricted bool `json:"restricted"`
// Suspended is true when sending is stopped entirely.
Suspended bool `json:"suspended"`
// Reason is the sentence a dashboard banner shows, when there is one.
Reason string `json:"reason,omitempty"`
}
OrgRisk is the workspace's sending posture: whether its volume is capped or stopped, and the plain-language reason. The detector evidence behind it is deliberately not returned.
type OrgTransferCatalog ¶ added in v0.3.0
type OrgTransferCatalog struct {
Groups []OrgDataGroupInfo `json:"groups"`
// FormatVersion is the archive layout this instance writes and reads.
FormatVersion int `json:"format_version"`
// MinPassphrase is the shortest secrets passphrase accepted.
MinPassphrase int `json:"min_passphrase"`
// RetentionDays is how long a finished export stays downloadable.
RetentionDays int `json:"retention_days"`
}
OrgTransferCatalog is what an archive can carry and the rules around it.
type Organization ¶
type Organization struct {
ID string `json:"id"`
Name string `json:"name"`
Slug *string `json:"slug,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"`
OwnerUserID string `json:"owner_user_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// DeletionScheduledFor is set while the workspace is pending a hard delete.
DeletionScheduledAt *time.Time `json:"deletion_scheduled_at,omitempty"`
DeletionScheduledFor *time.Time `json:"deletion_scheduled_for,omitempty"`
// PresenceShowOnline and PresenceShowActivity control team-presence
// privacy. With PresenceShowOnline false nobody is tracked at all; with
// PresenceShowActivity false, presence is shown without the
// viewing-or-editing detail.
PresenceShowOnline bool `json:"presence_show_online"`
PresenceShowActivity bool `json:"presence_show_activity"`
// ProductDescription, ICPNotes and VoiceProfile are the AI voice profile:
// organization grounding folded into every AI writing surface.
ProductDescription string `json:"product_description"`
ICPNotes string `json:"icp_notes"`
VoiceProfile string `json:"voice_profile"`
// InboxAgentEnabled opts the workspace into the inbox agent, which drafts
// a suggested reply on an inbound human reply. It never sends on its own.
InboxAgentEnabled bool `json:"inbox_agent_enabled"`
// member with the use-AI permission rather than only their author.
AssistantSharedHistory bool `json:"assistant_shared_history"`
Owner *User `json:"owner,omitempty"`
}
Organization is a workspace.
func (*Organization) PendingDeletion ¶
func (o *Organization) PendingDeletion() bool
PendingDeletion reports whether the workspace is scheduled for a hard delete.
type OrganizationCounts ¶
type OrganizationCounts struct {
TotalCampaigns int `json:"total_campaigns"`
ActiveCampaigns int `json:"active_campaigns"`
TotalContacts int `json:"total_contacts"`
TotalMembers int `json:"total_members"`
EmailAccounts int `json:"email_accounts"`
EmailsSentToday int `json:"emails_sent_today"`
}
OrganizationCounts is current usage against OrganizationLimits.
type OrganizationCreateParams ¶
type OrganizationCreateParams struct {
Name string `json:"name"`
}
OrganizationCreateParams creates a workspace.
type OrganizationLimits ¶
type OrganizationLimits struct {
MaxCampaigns *int `json:"max_campaigns,omitempty"`
MaxActiveCampaigns *int `json:"max_active_campaigns,omitempty"`
MaxTeamMembers *int `json:"max_team_members,omitempty"`
MaxEmailAccounts *int `json:"max_email_accounts,omitempty"`
MaxContacts *int `json:"max_contacts,omitempty"`
DailyCampaignLimit *int `json:"daily_campaign_limit,omitempty"`
}
OrganizationLimits are the ceilings the server actually enforces: the plan's, raised by any approved limit increase. A nil field is unlimited.
type OrganizationService ¶
type OrganizationService service
OrganizationService manages the organization (workspace): its settings and AI voice profile, its members, custom roles and invitations, plan limits and sending posture, whole-workspace export and import, and the danger zone.
These routes are session-only. They accept a JWT obtained from AuthService.Login (pass it with WithAccessToken or WithTokenSource) and reject a long-lived API key, because organization governance should never sit behind a static credential.
func (*OrganizationService) AcceptInvitation ¶
func (s *OrganizationService) AcceptInvitation(ctx context.Context, token string, opts ...RequestOption) (*Member, *Response, error)
AcceptInvitation joins the workspace an invite token points at.
func (*OrganizationService) CancelDeletion ¶
func (s *OrganizationService) CancelDeletion(ctx context.Context, reason string, opts ...RequestOption) (*Response, error)
CancelDeletion cancels a pending workspace deletion.
func (*OrganizationService) CancelInvitation ¶
func (s *OrganizationService) CancelInvitation(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
CancelInvitation withdraws a pending invitation.
func (*OrganizationService) CancelLimitRequest ¶
func (s *OrganizationService) CancelLimitRequest(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
CancelLimitRequest withdraws a pending request. Only its submitter may.
func (*OrganizationService) Create ¶
func (s *OrganizationService) Create(ctx context.Context, params *OrganizationCreateParams, opts ...RequestOption) (*Organization, *Response, error)
Create provisions a new workspace and returns it.
func (*OrganizationService) CreateExport ¶ added in v0.3.0
func (s *OrganizationService) CreateExport(ctx context.Context, params *OrgExportParams, opts ...RequestOption) (*OrgExportJob, *Response, error)
CreateExport starts an archive build in the background and returns the job (202). Poll it with OrganizationService.Export until OrgExportJob.Terminal, then fetch the file with OrganizationService.DownloadExport. Owner-only.
func (*OrganizationService) CreateImport ¶ added in v0.3.0
func (s *OrganizationService) CreateImport(ctx context.Context, file *FileUpload, params *OrgImportParams, opts ...RequestOption) (*OrgImportJob, *Response, error)
CreateImport uploads an archive and applies it to the current workspace in the background, returning the job (202). Poll it with OrganizationService.Import. Run OrganizationService.PreflightImport first: an import is irreversible. The upload is multipart (the archive as the file, the options as a JSON form field) and buffered in memory. Owner-only.
func (*OrganizationService) CreateRole ¶
func (s *OrganizationService) CreateRole(ctx context.Context, params *RoleCreateParams, opts ...RequestOption) (*Role, *Response, error)
CreateRole adds a custom role.
func (*OrganizationService) Current ¶
func (s *OrganizationService) Current(ctx context.Context, opts ...RequestOption) (*OrganizationWithLimits, *Response, error)
Current retrieves the workspace the session acts on, with its limits and current usage.
func (*OrganizationService) DangerZone ¶
func (s *OrganizationService) DangerZone(ctx context.Context, opts ...RequestOption) (*DangerZoneStatus, *Response, error)
DangerZone returns the workspace's deletion state and the confirmation phrase required to schedule one.
func (*OrganizationService) DeleteAvatar ¶
func (s *OrganizationService) DeleteAvatar(ctx context.Context, opts ...RequestOption) (*Response, error)
DeleteAvatar removes the workspace logo.
func (*OrganizationService) DeleteExport ¶ added in v0.3.0
func (s *OrganizationService) DeleteExport(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeleteExport removes an archive and its stored file. Owner-only.
func (*OrganizationService) DeleteRole ¶
func (s *OrganizationService) DeleteRole(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeleteRole removes a custom role.
func (*OrganizationService) DownloadExport ¶ added in v0.3.0
func (s *OrganizationService) DownloadExport(ctx context.Context, id string, w io.Writer, opts ...RequestOption) (*Response, error)
DownloadExport streams a completed archive (a zip) into w. The response carries the size in Content-Length and the digest in X-Archive-SHA256, so the copy can be verified against OrgExportJob.ArchiveSHA256. A job that has not completed, or whose archive has expired, answers 404. Owner-only, and audited. The download is not retried, so a failure mid-stream leaves w partially written.
func (*OrganizationService) Export ¶ added in v0.3.0
func (s *OrganizationService) Export(ctx context.Context, id string, opts ...RequestOption) (*OrgExportJob, *Response, error)
Export returns one archive build, for progress polling. Owner-only.
func (*OrganizationService) Exports ¶ added in v0.3.0
func (s *OrganizationService) Exports(ctx context.Context, opts ...RequestOption) ([]OrgExportJob, *Response, error)
Exports returns the workspace's recent archive builds, including expired ones. Owner-only.
func (*OrganizationService) Import ¶ added in v0.3.0
func (s *OrganizationService) Import(ctx context.Context, id string, opts ...RequestOption) (*OrgImportJob, *Response, error)
Import returns one import, for progress polling. Owner-only.
func (*OrganizationService) Imports ¶ added in v0.3.0
func (s *OrganizationService) Imports(ctx context.Context, opts ...RequestOption) ([]OrgImportJob, *Response, error)
Imports returns the workspace's recent imports. Owner-only.
func (*OrganizationService) InvitationLink ¶
func (s *OrganizationService) InvitationLink(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
InvitationLink returns the invite token for a pending invitation, so it can be shared out of band. Treat it as a credential: anyone holding it can join.
func (*OrganizationService) Invitations ¶
func (s *OrganizationService) Invitations(ctx context.Context, opts ...RequestOption) ([]Invitation, *Response, error)
Invitations returns the workspace's pending invitations.
func (*OrganizationService) Invite ¶
func (s *OrganizationService) Invite(ctx context.Context, params *InviteMemberParams, opts ...RequestOption) (*Invitation, *Response, error)
Invite invites someone to the workspace by email and returns the pending invitation.
func (*OrganizationService) LimitRequests ¶
func (s *OrganizationService) LimitRequests(ctx context.Context, orgID string, opts ...RequestOption) ([]LimitRequest, *Response, error)
LimitRequests returns the workspace's limit-increase requests.
func (*OrganizationService) Limits ¶
func (s *OrganizationService) Limits(ctx context.Context, opts ...RequestOption) (*LimitsAndCounts, *Response, error)
Limits returns the ceilings the server enforces for the workspace alongside current usage, the mailbox allowance and attachment storage.
func (*OrganizationService) List ¶
func (s *OrganizationService) List(ctx context.Context, opts ...RequestOption) ([]Member, *Response, error)
List returns the memberships the caller holds across every workspace.
func (*OrganizationService) Members ¶
func (s *OrganizationService) Members(ctx context.Context, opts ...RequestOption) ([]Member, *Response, error)
Members returns the workspace's members.
func (*OrganizationService) MyInvitations ¶
func (s *OrganizationService) MyInvitations(ctx context.Context, opts ...RequestOption) ([]Invitation, *Response, error)
MyInvitations returns the invitations awaiting the caller across every workspace.
func (*OrganizationService) PreflightImport ¶ added in v0.3.0
func (s *OrganizationService) PreflightImport(ctx context.Context, file *FileUpload, passphrase string, opts ...RequestOption) (*OrgImportPreflight, *Response, error)
PreflightImport uploads an archive and reports what applying it would do — what it holds, which rows conflict, which members are unknown — without writing anything. Pass the passphrase the archive was exported with to learn whether its secrets unseal; an empty one is fine. The upload is multipart and buffered in memory. Owner-only.
func (*OrganizationService) PreviewInvitation ¶
func (s *OrganizationService) PreviewInvitation(ctx context.Context, token string, opts ...RequestOption) (*InvitationPreview, *Response, error)
PreviewInvitation resolves an invite token to the workspace it points at, before the caller commits to joining. It needs no credentials: the token is the capability. The answer is the safe public view — see InvitationPreview — not the workspace-side Invitation row.
func (*OrganizationService) RemoveMember ¶
func (s *OrganizationService) RemoveMember(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
RemoveMember removes a member from the workspace.
func (*OrganizationService) RequestLimitIncrease ¶
func (s *OrganizationService) RequestLimitIncrease(ctx context.Context, orgID string, params *LimitRequestParams, opts ...RequestOption) (*LimitRequest, *Response, error)
RequestLimitIncrease files a request to raise one plan ceiling.
func (*OrganizationService) Risk ¶ added in v0.3.0
func (s *OrganizationService) Risk(ctx context.Context, opts ...RequestOption) (*OrgRisk, *Response, error)
Risk returns the workspace's sending posture: whether volume is capped or stopped, and why. Any member may read it; a workspace whose sending is limited should be able to see that it is.
func (*OrganizationService) Roles ¶
func (s *OrganizationService) Roles(ctx context.Context, opts ...RequestOption) ([]Role, *Response, error)
Roles returns the workspace's custom roles.
func (*OrganizationService) ScheduleDeletion ¶
func (s *OrganizationService) ScheduleDeletion(ctx context.Context, params *ScheduleDeletionParams, opts ...RequestOption) (*ScheduledDeletion, *Response, error)
ScheduleDeletion schedules the workspace for a delayed hard delete. It is owner-only, and Confirmation must match DangerZoneStatus.ConfirmationHint — the workspace name.
func (*OrganizationService) Switch ¶
func (s *OrganizationService) Switch(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Switch points the caller's session at another workspace they belong to. Subsequent requests on that session act on the new workspace.
func (*OrganizationService) TransferGroups ¶ added in v0.3.0
func (s *OrganizationService) TransferGroups(ctx context.Context, opts ...RequestOption) (*OrgTransferCatalog, *Response, error)
TransferGroups returns the data groups an archive can carry and the rules around one: format version, passphrase floor, export retention.
func (*OrganizationService) TransferOwnership ¶
func (s *OrganizationService) TransferOwnership(ctx context.Context, newOwnerUserID string, opts ...RequestOption) (*Response, error)
TransferOwnership hands the workspace to another member. Only the current owner may call it.
func (*OrganizationService) Update ¶
func (s *OrganizationService) Update(ctx context.Context, params *OrganizationUpdateParams, opts ...RequestOption) (*Organization, *Response, error)
Update modifies the current workspace.
func (*OrganizationService) UpdateMember ¶
func (s *OrganizationService) UpdateMember(ctx context.Context, id string, params *UpdateMemberParams, opts ...RequestOption) (*Member, *Response, error)
UpdateMember replaces a member's assigned roles.
func (*OrganizationService) UpdateRole ¶
func (s *OrganizationService) UpdateRole(ctx context.Context, id string, params *RoleUpdateParams, opts ...RequestOption) (*Role, *Response, error)
UpdateRole edits a custom role. Changes propagate to every member holding it.
func (*OrganizationService) UploadAvatar ¶
func (s *OrganizationService) UploadAvatar(ctx context.Context, file *FileUpload, opts ...RequestOption) (string, *Response, error)
UploadAvatar sets the workspace logo and returns the URL it is now served from. The image must be a PNG or JPEG, at most 2 MB and 1024 pixels on a side; anything else is refused. The previous logo is deleted.
type OrganizationUpdateParams ¶
type OrganizationUpdateParams struct {
Name *string `json:"name,omitempty"`
Slug *string `json:"slug,omitempty"`
PresenceShowOnline *bool `json:"presence_show_online,omitempty"`
PresenceShowActivity *bool `json:"presence_show_activity,omitempty"`
ProductDescription *string `json:"product_description,omitempty"`
ICPNotes *string `json:"icp_notes,omitempty"`
VoiceProfile *string `json:"voice_profile,omitempty"`
InboxAgentEnabled *bool `json:"inbox_agent_enabled,omitempty"`
}
OrganizationUpdateParams updates the current workspace. Nil fields are left unchanged; an empty string clears a text field.
type OrganizationWithLimits ¶
type OrganizationWithLimits struct {
Organization
Limits *OrganizationLimits `json:"limits,omitempty"`
Counts *OrganizationCounts `json:"counts,omitempty"`
}
OrganizationWithLimits is an organization together with its plan limits and current usage.
type OutreachService ¶
type OutreachService service
OutreachService reads and writes the organization-wide advanced outreach settings: the bounce pipeline, reply-intent classification, send-time optimization, preflight checks, the in-body unsubscribe line and the rest of the sending policy that campaigns inherit.
A campaign can override any of these for itself; see CampaignService.AdvancedSettings.
func (*OutreachService) Get ¶
func (s *OutreachService) Get(ctx context.Context, opts ...RequestOption) (*OutreachSettings, *Response, error)
Get returns the organization's advanced outreach settings.
func (*OutreachService) Update ¶
func (s *OutreachService) Update(ctx context.Context, settings *OutreachSettings, opts ...RequestOption) (*Response, error)
Update replaces the organization's advanced outreach settings wholesale, so start from OutreachService.Get rather than a zero value. Out-of-range values are clamped rather than refused. The API answers 204 with no body; read the stored result back with Get.
type OutreachSettings ¶
type OutreachSettings struct {
BouncePipeline BouncePipelineSettings `json:"bounce_pipeline"`
TaskReliability TaskReliabilitySettings `json:"task_reliability"`
ABTesting ABTestingSettings `json:"ab_testing"`
ReplyIntent ReplyIntentSettings `json:"reply_intent"`
SendTimeOptimization SendTimeOptimizationSettings `json:"send_time_optimization"`
Preflight PreflightValidationSettings `json:"preflight"`
Dashboard DeliverabilityDashboardSettings `json:"dashboard"`
// Unsubscribe is the in-body opt-out line campaigns inherit unless they
// set their own [Campaign.UnsubscribeMode].
Unsubscribe UnsubscribeSettings `json:"unsubscribe"`
// Custom carries forward-compatible keys the server understands but this
// SDK release does not model.
Custom map[string]any `json:"custom,omitempty"`
}
OutreachSettings is the full advanced-outreach policy, either for the organization or as a per-campaign override.
type OverallStats ¶
type OverallStats struct {
TotalEmailsSent int64 `json:"total_emails_sent"`
TotalOpens int64 `json:"total_opens"`
// MachineOpens are opens attributed to a mail-privacy proxy rather than a
// human, and are excluded from OpenRate.
MachineOpens int64 `json:"machine_opens"`
TotalClicks int64 `json:"total_clicks"`
// MachineClicks counts steps whose only clicks came from automated
// fetchers (security gateways walking the links). They are not part of
// TotalClicks, which only ever counts a person's click.
MachineClicks int64 `json:"machine_clicks"`
TotalReplies int64 `json:"total_replies"`
TotalBounces int64 `json:"total_bounces"`
OpenRate float64 `json:"open_rate"`
ClickRate float64 `json:"click_rate"`
ReplyRate float64 `json:"reply_rate"`
BounceRate float64 `json:"bounce_rate"`
ActiveCampaigns int `json:"active_campaigns"`
ActiveAccounts int `json:"active_accounts"`
}
OverallStats are the headline counters for the dashboard window.
type Page ¶
type Page[T any] struct { // Data holds the items on this page. Data []T `json:"data"` // Pagination holds the cursor metadata for this page. Pagination Pagination `json:"pagination"` // contains filtered or unexported fields }
Page is one page of a list endpoint's results. Beyond Data and Pagination it can fetch subsequent pages (Page.Next) or iterate every item across all pages (Page.All).
func (*Page[T]) All ¶
All returns an iterator over every item across all pages, fetching subsequent pages on demand. Iteration stops at the first error, which is yielded with the zero value of T:
for campaign, err := range page.All(ctx) {
if err != nil {
return err
}
fmt.Println(campaign.Name)
}
Example ¶
Auto-paging walks every page for you, fetching the next one only when the current one runs out.
package main
import (
"context"
"fmt"
"log"
"github.com/warmbly/warmbly-go"
)
func main() {
client, _ := warmbly.New(warmbly.WithAPIKey("wmbly_..."))
ctx := context.Background()
page, err := client.Emails.List(ctx, &warmbly.EmailListParams{Query: "acme.com"})
if err != nil {
log.Fatal(err)
}
for mailbox, err := range page.All(ctx) {
if err != nil {
log.Fatal(err)
}
fmt.Println(mailbox.Email, mailbox.WarmupActive())
}
}
Output:
func (*Page[T]) HasMore ¶
HasMore reports whether a further page is available. It requires both the has_more flag and a non-empty cursor, so a server that reports has_more with an empty/null cursor cannot drive an infinite re-fetch loop.
func (*Page[T]) Next ¶
Next fetches the following page. It returns ErrNoMorePages when the current page is the last.
func (*Page[T]) NextCursor ¶
NextCursor returns the opaque cursor for the next page, or "" if none.
type Pagination ¶
type Pagination struct {
// Total is the total number of matching items, when the API computes it.
Total *int64 `json:"total"`
// NextCursor is the opaque token for the next page, or nil on the last.
NextCursor *string `json:"next_cursor"`
// HasMore reports whether further pages exist.
HasMore bool `json:"has_more"`
}
Pagination is the cursor-based pagination envelope returned by list endpoints. Cursors are opaque: never construct or parse them, just pass NextCursor back to fetch the following page.
type PasskeyCredential ¶
type PasskeyCredential struct {
ID string `json:"id"`
Name string `json:"name"`
// Provider is the authenticator's origin, for example "icloud" or
// "android".
Provider string `json:"provider,omitempty"`
// CredentialID is the WebAuthn credential identifier.
CredentialID string `json:"credential_id"`
// Transports are how the authenticator can be reached, for example
// "internal" or "hybrid".
Transports []string `json:"transports"`
// BackupState reports whether the credential is synced to a cloud keychain
// rather than bound to one device.
BackupState bool `json:"backup_state"`
CreatedAt time.Time `json:"created_at"`
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
}
PasskeyCredential is one registered WebAuthn credential.
type PasskeyLoginChallenge ¶ added in v0.3.0
type PasskeyLoginChallenge struct {
// Session is the opaque handle for [AuthService.FinishPasskeyLogin].
Session string `json:"session"`
// Options is the raw WebAuthn credential-request options, for the
// authenticator.
Options json.RawMessage `json:"options"`
}
PasskeyLoginChallenge is the start of a passkey sign-in: the WebAuthn request options for the authenticator and the handle to return with its assertion.
type PendingTool ¶
type PendingTool struct {
MessageID string `json:"message_id"`
ToolCallID string `json:"tool_call_id"`
ToolName string `json:"tool_name"`
// Risk is how consequential the call is, for example "send".
Risk string `json:"risk"`
// Args is the exact payload the tool would run with, and ArgsSummary a
// human-readable rendering of it.
Args json.RawMessage `json:"args"`
ArgsSummary string `json:"args_summary,omitempty"`
}
PendingTool is a tool call paused for human approval.
type Permission ¶
type Permission struct {
// Name is the stable identifier, for example "READ_CAMPAIGNS".
Name string `json:"name"`
Value uint64 `json:"value"`
// Description is human-readable copy for a permission picker.
Description string `json:"description"`
// Category groups the bit as "read", "write", "bulk" or "special".
Category string `json:"category"`
}
Permission describes one scope bit the API advertises.
type PermissionCatalog ¶
type PermissionCatalog struct {
Permissions []Permission `json:"permissions"`
Presets PermissionPresets `json:"presets"`
}
PermissionCatalog is the full set of API scopes plus the server's preset masks. Prefer the presets over hard-coding a mask when you want "everything": the server's value stays current as scopes are added.
type PermissionPresets ¶
type PermissionPresets struct {
ReadOnly uint64 `json:"read_only"`
FullAccess uint64 `json:"full_access"`
}
PermissionPresets are the server-side preset masks.
type Pipeline ¶
type Pipeline struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Position int `json:"position"`
// Stages is populated on reads that hydrate the pipeline.
Stages []PipelineStage `json:"stages,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Pipeline is a named deal pipeline: an ordered set of stages deals move through.
type PipelineCreateParams ¶
type PipelineCreateParams struct {
Name string `json:"name"`
Stages []StageCreateParams `json:"stages,omitempty"`
}
PipelineCreateParams creates a pipeline, optionally with its initial stages.
type PipelineStage ¶
type PipelineStage struct {
ID string `json:"id"`
PipelineID string `json:"pipeline_id"`
Name string `json:"name"`
Color string `json:"color"`
Position int `json:"position"`
// DealCount is set on reads that count the stage's deals.
DealCount int `json:"deal_count,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
PipelineStage is one column of a pipeline.
type PipelineUpdateParams ¶
type PipelineUpdateParams struct {
Name *string `json:"name,omitempty"`
}
PipelineUpdateParams renames a pipeline.
type Plan ¶
type Plan struct {
ID string `json:"id"`
Name *string `json:"name,omitempty"`
MaxContacts uint `json:"max_contacts"`
DailyEmails uint `json:"daily_emails"`
AIGeneration bool `json:"ai_generation"`
AccountLimit uint `json:"account_limit"`
Price float32 `json:"price"`
DiscountedPrice float32 `json:"discounted_price"`
// Duration is [DurationMonth] or [DurationYear].
Duration string `json:"duration"`
// Savings is the percentage saved against the monthly price.
Savings uint8 `json:"savings"`
// Public reports whether the plan is offered on the pricing page.
Public bool `json:"public"`
StripePriceID *string `json:"stripe_price_id,omitempty"`
StripePriceIDYearly *string `json:"stripe_price_id_yearly,omitempty"`
StripeProductID *string `json:"stripe_product_id,omitempty"`
DedicatedWorkers int `json:"dedicated_workers"`
DailyCampaignLimit *int `json:"daily_campaign_limit,omitempty"`
MaxCampaigns *int `json:"max_campaigns,omitempty"`
MaxActiveCampaigns *int `json:"max_active_campaigns,omitempty"`
MaxTeamMembers *int `json:"max_team_members,omitempty"`
MaxEmailAccounts *int `json:"max_email_accounts,omitempty"`
// MonthlyCredits is the AI credit grant included each month.
MonthlyCredits int `json:"monthly_credits"`
// ReferralRewardPercent is the share of this plan's month-equivalent
// price a referrer earns when an invitee converts to it; 100 is a full
// month.
ReferralRewardPercent int `json:"referral_reward_percent"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
Plan is one purchasable plan and the ceilings it carries.
type PlanChangePreview ¶ added in v0.3.0
type PlanChangePreview struct {
CurrentPlan *Plan `json:"current_plan"`
NewPlan *Plan `json:"new_plan"`
// ProrationAmount is the credit or charge for the unused part of the
// current period, and AmountDue what the next invoice comes to. Both are
// in the smallest unit of Currency, and either can be negative.
ProrationAmount int64 `json:"proration_amount"`
AmountDue int64 `json:"amount_due"`
// NextBillingDate is when that invoice falls due.
NextBillingDate time.Time `json:"next_billing_date"`
Currency string `json:"currency"`
}
PlanChangePreview is what a plan change would cost, computed by the payment provider without making the change.
type PoolLinkCode ¶ added in v0.3.0
type PoolLinkCode struct {
ID string `json:"id"`
// UserCode is the code the operator typed in.
UserCode string `json:"user_code"`
// InstanceName, InstanceURL and InstanceVersion are what the instance
// claimed about itself in [PoolLinkStartParams]; nothing here is verified.
InstanceName string `json:"instance_name"`
InstanceURL string `json:"instance_url"`
InstanceVersion string `json:"instance_version"`
// Status is one of the PoolLinkCode* constants.
Status string `json:"status"`
// OrganizationID and InstanceID are set once the code has been approved.
OrganizationID *string `json:"organization_id,omitempty"`
InstanceID *string `json:"instance_id,omitempty"`
// ExpiresAt is when an unsettled code stops being approvable.
ExpiresAt time.Time `json:"expires_at"`
CreatedAt time.Time `json:"created_at"`
}
PoolLinkCode describes a pending handshake to the member about to settle it.
type PoolLinkCodeGrant ¶ added in v0.3.0
type PoolLinkCodeGrant struct {
// DeviceCode is the secret half: keep it on the instance and send it only
// to [PoolLinkService.Poll].
DeviceCode string `json:"device_code"`
// UserCode is the short code the operator types in at VerificationURL.
UserCode string `json:"user_code"`
// VerificationURL is the page where a signed-in member approves the code.
// It already carries the user code as a query parameter.
VerificationURL string `json:"verification_url"`
// ExpiresIn is how long the code stays approvable, in seconds (15 minutes
// at the time of writing).
ExpiresIn int `json:"expires_in"`
// Interval is the minimum number of seconds between polls.
Interval int `json:"interval"`
}
PoolLinkCodeGrant is the device-code grant that opens a handshake.
type PoolLinkInstance ¶ added in v0.3.0
type PoolLinkInstance struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
URL string `json:"url"`
// Version is the build the instance most recently reported.
Version string `json:"version"`
// CreatedBy is the member who approved the link, when still known.
CreatedBy *string `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at"`
// LastSeenAt is the instance's most recent authenticated call.
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
// RevokedAt is set once the link has been ended from either side.
RevokedAt *time.Time `json:"revoked_at,omitempty"`
// MailboxCount is how many of the instance's mailboxes are enrolled in the
// pool. It is filled by [PoolLinkService.ListInstances] only and is zero
// on the instance returned from [PoolLinkService.ApproveCode].
MailboxCount int `json:"mailbox_count"`
}
PoolLinkInstance is a linked self-hosted instance as the workspace sees it.
type PoolLinkInstanceInfo ¶ added in v0.3.0
type PoolLinkInstanceInfo struct {
Instance PoolLinkInstance `json:"instance"`
Organization PoolLinkOrganization `json:"organization"`
Plan PoolLinkPlan `json:"plan"`
}
PoolLinkInstanceInfo is the cloud's status document for one linked instance, as the instance itself sees it. The self-hosted dashboard surfaces it through CloudLinkStatus.Info.
type PoolLinkInstanceList ¶ added in v0.3.0
type PoolLinkInstanceList struct {
Data []PoolLinkInstance `json:"data"`
Plan PoolLinkPlan `json:"plan"`
}
PoolLinkInstanceList is the answer to PoolLinkService.ListInstances: the linked instances plus the allowance they share.
type PoolLinkMailboxState ¶ added in v0.3.0
type PoolLinkMailboxState struct {
// RemoteID is the mailbox's ID on the self-hosted instance;
// EmailAccountID is its ID in the cloud workspace.
RemoteID string `json:"remote_id"`
EmailAccountID string `json:"email_account_id"`
Email string `json:"email"`
Name string `json:"name"`
// Provider is [ProviderGmail], [ProviderOutlook] or [ProviderSMTPIMAP].
Provider string `json:"provider"`
// Status is the cloud mailbox's connection state, for example
// [MailboxStatusActive].
Status string `json:"status"`
EnrolledAt time.Time `json:"enrolled_at"`
// Managed is true when the cloud holds the only credential (a Google or
// Microsoft sign-in on Warmbly's own OAuth apps) and the instance sends
// with brokered short-lived tokens.
Managed bool `json:"managed"`
Warmup *PoolLinkWarmupStatus `json:"warmup,omitempty"`
Health *PoolLinkWarmupHealth `json:"health,omitempty"`
// SentToday, Sent7d, Replied7d and SpamPlaced7d are warmup counters.
SentToday int `json:"sent_today"`
Sent7d int `json:"sent_7d"`
Replied7d int `json:"replied_7d"`
SpamPlaced7d int `json:"spam_placed_7d"`
// Errors are the cloud mailbox's open account errors.
Errors []AccountError `json:"errors,omitempty"`
// AuthState is the cloud's view of the mailbox credential.
AuthState string `json:"auth_state"`
Settings PoolLinkWarmupSettings `json:"settings"`
}
PoolLinkMailboxState is the cloud's per-mailbox view of an enrolled mailbox, shown in both dashboards.
type PoolLinkOrganization ¶ added in v0.3.0
PoolLinkOrganization is the cloud workspace a link belongs to.
type PoolLinkPlan ¶ added in v0.3.0
type PoolLinkPlan struct {
// Tier is [PoolLinkTierFree] or [PoolLinkTierPaid].
Tier string `json:"tier"`
// MailboxLimit is the cap on enrolled mailboxes across every linked
// instance, or nil when unlimited.
MailboxLimit *int `json:"mailbox_limit"`
// Enrolled is how many linked mailboxes currently count against the cap.
Enrolled int `json:"enrolled"`
// PriceUSD is the monthly price of the paid tier, for an upgrade prompt.
PriceUSD int `json:"price_usd"`
// UpgradeURL is where to send the operator to upgrade; empty when billing
// is off or the paid tier has no price.
UpgradeURL string `json:"upgrade_url,omitempty"`
// WarmupEntitled is false when the cloud workspace itself is not allowed
// to warm, in which case linked mailboxes will not warm either.
WarmupEntitled bool `json:"warmup_entitled"`
}
PoolLinkPlan is the pool allowance the cloud computes for a workspace's linked instances.
type PoolLinkPollResult ¶ added in v0.3.0
type PoolLinkPollResult struct {
// Status is [PoolLinkCodePending] or [PoolLinkCodeApproved]; a denied or
// spent code is reported as an error, not a status.
Status string `json:"status"`
// InstanceID is set once approved.
InstanceID *string `json:"instance_id,omitempty"`
// InstanceToken is the instance's long-lived credential for
// /pool-link/instance/*. It is delivered exactly once: store it
// immediately, because the next poll fails with "pool_link_code_used".
InstanceToken string `json:"instance_token,omitempty"`
// Organization is the workspace the instance was linked to, once approved.
Organization *PoolLinkOrganization `json:"organization,omitempty"`
}
PoolLinkPollResult is one answer to PoolLinkService.Poll.
type PoolLinkService ¶ added in v0.3.0
type PoolLinkService service
PoolLinkService is the hosted (cloud) side of the self-hosted warmup pool link: a self-hosted Warmbly instance asks to warm its mailboxes in this workspace's pool, a member approves it, and the workspace then lists and unlinks the instances it has admitted.
Linking is a device-code handshake. The instance calls PoolLinkService.StartCode before it holds any credential and shows the returned user code to its operator; that operator signs in to Warmbly Cloud, reviews the code with PoolLinkService.DescribeCode and settles it with PoolLinkService.ApproveCode or PoolLinkService.DenyCode; meanwhile the instance loops on PoolLinkService.Poll (or PoolLinkService.WaitForApproval) until the code is approved and its instance token is delivered, once.
Only StartCode and Poll are public: they need no credential at all and share the per-IP sign-in rate budget, so a runaway poll loop can lock the address out of the browser login for the rest of the window. Every other route is session-only: it needs a token from AuthService.Login, never an API key, because approving a code mints a credential for a third party. Listing and revoking instances additionally need the manage-settings organization permission.
The instance's own machine-to-machine surface, /pool-link/instance/* (status, enrollment, brokered access tokens), accepts only the instance token minted by the handshake and is deliberately not modeled here; the self-hosted dashboard reaches it through CloudLinkService.
On a deployment that has the pool link switched off every route answers 501 Not Implemented.
func (*PoolLinkService) ApproveCode ¶ added in v0.3.0
func (s *PoolLinkService) ApproveCode(ctx context.Context, userCode, organizationID string, opts ...RequestOption) (*PoolLinkInstance, *Response, error)
ApproveCode admits the instance behind userCode into the workspace organizationID and returns the new linked instance. The instance collects its token on its next poll.
organizationID is the workspace to link to, which need not be the session's active one; pass "" to fall back to the session's workspace. The caller needs the manage-settings permission in that workspace. Session-only; the call is recorded in the workspace audit log.
A code that is no longer pending fails with "pool_link_code_used".
func (*PoolLinkService) DenyCode ¶ added in v0.3.0
func (s *PoolLinkService) DenyCode(ctx context.Context, userCode string, opts ...RequestOption) (*Response, error)
DenyCode declines the handshake behind userCode. The instance's next poll fails with "pool_link_denied" and the code cannot be approved afterwards. Session-only.
func (*PoolLinkService) DescribeCode ¶ added in v0.3.0
func (s *PoolLinkService) DescribeCode(ctx context.Context, userCode string, opts ...RequestOption) (*PoolLinkCode, *Response, error)
DescribeCode shows the signed-in member what they are about to link: the instance's self-reported name, URL and version, and whether the code is still pending. Session-only.
An unknown or expired code fails with "pool_link_code_not_found".
func (*PoolLinkService) ListInstances ¶ added in v0.3.0
func (s *PoolLinkService) ListInstances(ctx context.Context, opts ...RequestOption) (*PoolLinkInstanceList, *Response, error)
ListInstances lists the instances linked to the session's workspace, together with the pool allowance they share. Session-only; needs the manage-settings permission.
func (*PoolLinkService) Poll ¶ added in v0.3.0
func (s *PoolLinkService) Poll(ctx context.Context, deviceCode string, opts ...RequestOption) (*PoolLinkPollResult, *Response, error)
Poll asks once whether the code behind deviceCode has been approved. While nobody has settled it the result is PoolLinkCodePending; once a member approves it the result is PoolLinkCodeApproved with the instance token, which is delivered on this one call only.
A denied code fails with an *Error whose Code is "pool_link_denied"; an already collected one with "pool_link_code_used"; an unknown or expired one with "pool_link_code_not_found". Wait at least PoolLinkCodeGrant.Interval seconds between calls: the route is public and draws on the per-IP sign-in budget.
func (*PoolLinkService) RevokeInstance ¶ added in v0.3.0
func (s *PoolLinkService) RevokeInstance(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
RevokeInstance unlinks an instance: its token stops working, every mailbox it enrolled leaves the pool and their credentials are deleted on the cloud. The instance's next call fails with "pool_link_revoked" and its local warmup takes over. Session-only; needs the manage-settings permission and is recorded in the workspace audit log.
func (*PoolLinkService) StartCode ¶ added in v0.3.0
func (s *PoolLinkService) StartCode(ctx context.Context, params *PoolLinkStartParams, opts ...RequestOption) (*PoolLinkCodeGrant, *Response, error)
StartCode opens a device-code handshake on behalf of a self-hosted instance that holds no credential yet. Show PoolLinkCodeGrant.UserCode and PoolLinkCodeGrant.VerificationURL to the operator, keep PoolLinkCodeGrant.DeviceCode private, and follow up with PoolLinkService.WaitForApproval.
Public and per-IP rate limited; the client's credential, if any, is sent but ignored.
func (*PoolLinkService) WaitForApproval ¶ added in v0.3.0
func (s *PoolLinkService) WaitForApproval(ctx context.Context, grant *PoolLinkCodeGrant, opts ...RequestOption) (*PoolLinkPollResult, error)
WaitForApproval polls grant every PoolLinkCodeGrant.Interval seconds (never faster than once a second) until the code is approved, the server reports a terminal error, or ctx is done. On success the result carries the one-time instance token.
The server retires an unapproved code after PoolLinkCodeGrant.ExpiresIn seconds, after which the loop ends with a "pool_link_code_not_found" error; bound ctx yourself to give up sooner.
type PoolLinkStartParams ¶ added in v0.3.0
type PoolLinkStartParams struct {
// InstanceName is the label the approval page shows, typically the host
// name or the operator's INSTANCE_NAME.
InstanceName string `json:"instance_name"`
// InstanceURL is the instance's public base URL.
InstanceURL string `json:"instance_url"`
// InstanceVersion is the instance's build, for support and compatibility.
InstanceVersion string `json:"instance_version"`
}
PoolLinkStartParams identifies the instance that wants to link, as shown to the approving member.
type PoolLinkWarmupHealth ¶ added in v0.3.0
type PoolLinkWarmupHealth struct {
// State is one of the Band* constants: [BandHealthy], [BandWatch],
// [BandThrottled], [BandQuarantined] or [BandBlocked].
State string `json:"state"`
Score float64 `json:"score"`
// Reason explains a state other than healthy.
Reason string `json:"reason,omitempty"`
SpamScore int `json:"spam_score"`
// BlockedUntil is when a quarantine or block lifts on its own.
BlockedUntil *time.Time `json:"blocked_until,omitempty"`
EvaluatedAt *time.Time `json:"evaluated_at,omitempty"`
}
PoolLinkWarmupHealth is the pool's reputation verdict on an enrolled mailbox.
type PoolLinkWarmupRampHold ¶ added in v0.3.0
type PoolLinkWarmupRampHold struct {
// Placements and Sends cover the last 48 hours.
Placements int `json:"placements"`
Sends int `json:"sends"`
VolumeCut bool `json:"volume_cut"`
// ResumesAt is when the ramp climbs again if nothing else lands.
ResumesAt time.Time `json:"resumes_at"`
}
PoolLinkWarmupRampHold explains a frozen ramp. It is present for the whole freeze; VolumeCut says whether today's volume is also reduced, which lasts a shorter window.
type PoolLinkWarmupSettings ¶ added in v0.3.0
type PoolLinkWarmupSettings struct {
// Base is the starting daily volume, Max the ceiling and Increase the
// daily step between them.
Base int `json:"base"`
Max int `json:"max"`
Increase int `json:"increase"`
// ReplyRate is the percentage of warmup mail that gets a reply.
ReplyRate int `json:"reply_rate"`
// StartTime and EndTime bound the sending window, as "HH:MM".
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
// Days is a bitmask of weekdays the mailbox warms on.
Days int `json:"days"`
Timezone string `json:"timezone"`
}
PoolLinkWarmupSettings is the ramp an enrolled mailbox warms on. It is copied from the mailbox's own settings on the instance at enrollment time; zero values mean the cloud's defaults.
type PoolLinkWarmupStatus ¶ added in v0.3.0
type PoolLinkWarmupStatus struct {
Enabled bool `json:"enabled"`
Paused bool `json:"paused"`
PausedAt *time.Time `json:"paused_at,omitempty"`
// StartedAt is when the ramp began.
StartedAt time.Time `json:"started_at"`
// CurrentVolume is today's sends so far against TargetVolume, today's
// ramp target, which climbs toward MaxVolume.
CurrentVolume int `json:"current_volume"`
TargetVolume int `json:"target_volume"`
MaxVolume int `json:"max_volume"`
ReplyRate int `json:"reply_rate"`
DaysActive int `json:"days_active"`
// RampHold explains a ramp that is not climbing, so a target below the
// plain ramp is never an unexplained drop.
RampHold *PoolLinkWarmupRampHold `json:"ramp_hold,omitempty"`
}
PoolLinkWarmupStatus is the live ramp state of an enrolled mailbox.
type PoolLinkWorkspaceMailbox ¶ added in v0.3.0
type PoolLinkWorkspaceMailbox struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
// Provider is [ProviderGmail] or [ProviderOutlook].
Provider string `json:"provider"`
Status string `json:"status"`
}
PoolLinkWorkspaceMailbox is a Google or Microsoft mailbox connected directly on the cloud workspace that a linked instance may adopt.
type PreflightCheck ¶
type PreflightCheck struct {
Key string `json:"key"`
Passed bool `json:"passed"`
// Severity is how much a failure matters, for example "error" or "warning".
Severity string `json:"severity"`
Message string `json:"message"`
Remediation string `json:"remediation,omitempty"`
}
PreflightCheck is a single pre-launch check.
type PreflightResult ¶
type PreflightResult struct {
ID string `json:"id,omitempty"`
OrganizationID string `json:"organization_id,omitempty"`
CampaignID string `json:"campaign_id"`
// Passed is false when any blocking check failed.
Passed bool `json:"passed"`
// Score is a 0-100 readiness score.
Score int `json:"score"`
Checks []PreflightCheck `json:"checks"`
Recommendations []string `json:"recommendations,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
}
PreflightResult is the outcome of the pre-launch checks for a campaign.
type PreflightValidationSettings ¶
type PreflightValidationSettings struct {
Enabled bool `json:"enabled"`
CheckTrackingDomain bool `json:"check_tracking_domain"`
CheckUnsubscribeHeader bool `json:"check_unsubscribe_header"`
CheckABVariantConfigured bool `json:"check_ab_variant_configured"`
CheckDailyLimit bool `json:"check_daily_limit"`
CheckScheduleWindow bool `json:"check_schedule_window"`
// CheckContentScore scores each step's copy for spam signals, at preflight
// and again per send against the rendered text. It is advisory: it warns
// and never blocks a send. On by default.
CheckContentScore bool `json:"check_content_score"`
// MinContentScore is the 1-100 floor below which copy is flagged (default
// 60). Values outside the range are clamped server-side.
MinContentScore int `json:"min_content_score"`
}
PreflightValidationSettings selects the checks run before a campaign starts.
type ProfileUpdateParams ¶
type ProfileUpdateParams struct {
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
}
ProfileUpdateParams updates the caller's own name.
type ProviderPlacement ¶ added in v0.3.0
type ProviderPlacement struct {
Provider string `json:"provider"`
Samples int64 `json:"samples"`
Inbox int64 `json:"inbox"`
Promotions int64 `json:"promotions"`
Spam int64 `json:"spam"`
Other int64 `json:"other"`
InboxRate float64 `json:"inbox_rate"`
SpamRate float64 `json:"spam_rate"`
}
ProviderPlacement is one recipient provider's seed placement rollup: where the seed messages landed.
type PushContactResult ¶
type PushContactResult struct {
ContactID string `json:"contact_id"`
Email string `json:"email,omitempty"`
OK bool `json:"ok"`
Error string `json:"error,omitempty"`
}
PushContactResult is one contact's outcome in a push.
type PushResult ¶
type PushResult struct {
Provider string `json:"provider"`
Pushed int `json:"pushed"`
Failed int `json:"failed"`
Results []PushContactResult `json:"results"`
}
PushResult reports the outcome of pushing contacts to a provider.
type RateLimit ¶
type RateLimit struct {
// Limit is the ceiling of requests permitted in the current window.
Limit int
// Remaining is the number of requests left in the current window.
Remaining int
// Policy is the raw policy string, e.g. "60;w=60".
Policy string
// RetryAfter is how long to wait before retrying, when provided.
RetryAfter time.Duration
}
RateLimit is the per-key rate-limit state reported on each response.
type RealtimeInfo ¶
type RealtimeInfo struct {
// WebsocketURL is the endpoint to dial.
WebsocketURL string `json:"websocket_url"`
// Topics are the channels this caller may subscribe to.
Topics []string `json:"topics"`
}
RealtimeInfo tells a client where the realtime gateway lives.
type RealtimeRateLimits ¶ added in v0.3.0
type RealtimeRateLimits struct {
LimitWSMessagePM int `json:"limit_ws_message_pm"`
LimitWSJoinPM int `json:"limit_ws_join_pm"`
LimitWSEventPM int `json:"limit_ws_event_pm"`
MaxConnections int `json:"max_connections"`
}
RealtimeRateLimits are the plan's websocket ceilings: messages, channel joins and events per minute, and concurrent connections.
type ReferralAttribution ¶
type ReferralAttribution struct {
ID string `json:"id"`
ReferralCodeID *string `json:"referral_code_id,omitempty"`
ReferrerUserID string `json:"referrer_user_id"`
ReferrerOrgID string `json:"referrer_org_id"`
InviteeOrgID string `json:"invitee_org_id"`
InviteeUserID *string `json:"invitee_user_id,omitempty"`
// Status is one of the ReferralStatus* constants.
Status string `json:"status"`
RewardCents int64 `json:"reward_cents"`
RewardCurrency string `json:"reward_currency"`
QualifiedAt *time.Time `json:"qualified_at,omitempty"`
RewardedAt *time.Time `json:"rewarded_at,omitempty"`
VoidedAt *time.Time `json:"voided_at,omitempty"`
VoidReason *string `json:"void_reason,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ReferralAttribution is one referred workspace and where its reward stands.
type ReferralCode ¶ added in v0.3.0
type ReferralCode struct {
ID string `json:"id"`
OwnerUserID string `json:"owner_user_id"`
OwnerOrgID string `json:"owner_org_id"`
// Code is the token that goes in a share link's ?ref= parameter and in
// [LoginParams.ReferralCode].
Code string `json:"code"`
// DiscountCodeID is the promotion an invitee redeems by signing up with
// the code, when the deployment attaches one.
DiscountCodeID *string `json:"discount_code_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ReferralCode is the workspace's own referral code, as returned by BillingService.EnsureReferralCode.
type ReferralEarning ¶
type ReferralEarning struct {
ID string `json:"id"`
OrgID string `json:"org_id"`
// AttributionID is the referral the movement settles, when there is one.
AttributionID *string `json:"attribution_id,omitempty"`
// AmountCents is positive for a reward and negative for a clawback.
AmountCents int64 `json:"amount_cents"`
Currency string `json:"currency"`
// Reason names what moved the balance.
Reason string `json:"reason"`
// BalanceAfterCents is the running balance once this movement applied.
BalanceAfterCents int64 `json:"balance_after_cents"`
// StripeCustomerBalanceTxnID links the movement to the provider-side
// customer balance transaction it produced.
StripeCustomerBalanceTxnID *string `json:"stripe_customer_balance_txn_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
ReferralEarning is one movement in the referral credit ledger.
type ReferralSummary ¶
type ReferralSummary struct {
Code string `json:"code"`
Currency string `json:"currency"`
// InviteePercentOff and InviteeMonths are what someone signing up through
// the link receives.
InviteePercentOff int `json:"invitee_percent_off"`
InviteeMonths int `json:"invitee_months"`
// BalanceCents is the credit available now; LifetimeEarnedCents is the
// running total.
BalanceCents int64 `json:"balance_cents"`
LifetimeEarnedCents int64 `json:"lifetime_earned_cents"`
TotalReferred int `json:"total_referred"`
Pending int `json:"pending"`
Qualified int `json:"qualified"`
Rewarded int `json:"rewarded"`
}
ReferralSummary is the workspace's referral position.
type ReplyIntentSettings ¶
type ReplyIntentSettings struct {
Enabled bool `json:"enabled"`
PositiveKeywords []string `json:"positive_keywords"`
NegativeKeywords []string `json:"negative_keywords"`
OutOfOfficeKeywords []string `json:"out_of_office_keywords"`
QuestionKeywords []string `json:"question_keywords"`
AutoCreateCRMTask bool `json:"auto_create_crm_task"`
AutoPauseOnNegative bool `json:"auto_pause_on_negative"`
AutoSuppressOnUnsubWord bool `json:"auto_suppress_on_unsubscribe_keyword"`
}
ReplyIntentSettings configures keyword-based classification of inbound replies and the actions taken on each class.
type RequestOption ¶
type RequestOption func(*requestConfig)
RequestOption customizes a single API call. Every service method accepts a variadic list of them.
func WithIdempotencyKey ¶
func WithIdempotencyKey(key string) RequestOption
WithIdempotencyKey attaches an Idempotency-Key to a mutating request. Retrying the same key with the same method, path and body replays the original response instead of performing the operation twice. The key must be 1-255 visible ASCII characters; a UUID is a good choice.
_, _, err := client.Emails.Send(ctx, id, params, warmbly.WithIdempotencyKey(key))
Example ¶
An idempotency key makes a retry safe on anything that sends mail or spends money: repeating the key replays the original response instead of acting twice.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/warmbly/warmbly-go"
)
func main() {
client, _ := warmbly.New(warmbly.WithAPIKey("wmbly_..."))
result, resp, err := client.Emails.Send(context.Background(), "mailbox_id", &warmbly.SendEmailParams{
To: []string{"prospect@example.com"},
Subject: "Hello",
BodyPlain: "Hi there.",
}, warmbly.WithIdempotencyKey("order-4171-welcome"))
if err != nil {
log.Fatal(err)
}
if resp.IdempotentReplayed {
fmt.Println("already sent; replayed the original response")
}
fmt.Println("queued", result.TaskID, "for", result.ScheduledAt.Format(time.RFC3339))
}
Output:
func WithQueryParam ¶
func WithQueryParam(key, value string) RequestOption
WithQueryParam sets a query parameter on a single request. Use it to reach filters newer than this SDK release without waiting for a typed field.
func WithRequestHeader ¶
func WithRequestHeader(key, value string) RequestOption
WithRequestHeader sets a header on a single request, overriding any client default of the same name.
type ResearchArtifact ¶
type ResearchArtifact struct {
What string `json:"what"`
Where string `json:"where"`
When string `json:"when,omitempty"`
URL string `json:"url"`
}
ResearchArtifact is something public the contact produced.
type ResearchCompany ¶
type ResearchCompany struct {
Summary string `json:"summary,omitempty"`
Industry string `json:"industry,omitempty"`
SizeEstimate string `json:"size_estimate,omitempty"`
SellsTo string `json:"sells_to,omitempty"`
TechOrStackSignals []string `json:"tech_or_stack_signals,omitempty"`
}
ResearchCompany is what a run learned about the contact's company.
type ResearchHook ¶
type ResearchHook struct {
BasedOn string `json:"based_on"`
WhyRelevant string `json:"why_relevant"`
OpenerLine string `json:"opener_line"`
}
ResearchHook is a suggested opener grounded in a signal.
type ResearchPerson ¶
type ResearchPerson struct {
RoleConfirmed bool `json:"role_confirmed"`
Title string `json:"title,omitempty"`
PublicArtifacts []ResearchArtifact `json:"public_artifacts,omitempty"`
}
ResearchPerson is what a run learned about the contact themselves.
type ResearchResult ¶
type ResearchResult struct {
Company *ResearchCompany `json:"company,omitempty"`
Person *ResearchPerson `json:"person,omitempty"`
Signals []ResearchSignal `json:"signals,omitempty"`
Hooks []ResearchHook `json:"hooks,omitempty"`
// CustomFieldUpdates are contact custom fields the run proposes.
CustomFieldUpdates map[string]string `json:"custom_field_updates,omitempty"`
ResearchNotes string `json:"research_notes,omitempty"`
NothingFound bool `json:"nothing_found"`
}
ResearchResult is what a run found. Every signal and artifact carries a source URL; the server rejects anything uncited.
type ResearchRun ¶
type ResearchRun struct {
ID string `json:"id"`
OrgID string `json:"org_id"`
ContactID string `json:"contact_id"`
RequestedBy *string `json:"requested_by,omitempty"`
// Status is one of the Research* constants.
Status string `json:"status"`
Objective string `json:"objective"`
Result ResearchResult `json:"result"`
Error string `json:"error,omitempty"`
CreditsCharged int `json:"credits_charged"`
ModelUsed string `json:"model_used"`
TokensUsed int `json:"tokens_used"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ResearchRun is one AI research attempt against a contact. Runs spend AI credits.
type ResearchSignal ¶
type ResearchSignal struct {
Type string `json:"type"`
Fact string `json:"fact"`
When string `json:"when,omitempty"`
URL string `json:"url"`
Confidence string `json:"confidence"`
}
ResearchSignal is a cited fact. Confidence is "high", "medium" or "low".
type Response ¶
type Response struct {
*http.Response
// RateLimit holds the parsed X-RateLimit-* headers, when present.
RateLimit RateLimit
// RequestID is the server-assigned request identifier (X-Request-ID).
RequestID string
// APIVersion is the API surface that served the request (for example
// "v1"), taken from the API-Version header.
APIVersion string
// Deprecation is the raw Deprecation header, set when the endpoint is on
// its way out.
Deprecation string
// Sunset is the raw Sunset header: the date after which a deprecated
// endpoint stops responding.
Sunset string
// Warning is the raw Warning header carrying migration advice.
Warning string
// IdempotentReplayed reports whether the server replayed a stored response
// for a repeated Idempotency-Key rather than acting again.
IdempotentReplayed bool
}
Response wraps the underlying *http.Response with parsed Warmbly metadata. The body has already been consumed and closed by the time a Response is returned.
func (*Response) Deprecated ¶
Deprecated reports whether the server marked this endpoint as deprecated.
type Role ¶
type Role struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Description string `json:"description"`
Color string `json:"color"`
// Permissions is the role's grant, an OR of the OrgPerm* bits.
Permissions uint16 `json:"permissions"`
MemberCount int `json:"member_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Role is an organization-scoped custom role: a named permission set members are assigned to. Editing a role writes through to every member holding it.
type RoleCreateParams ¶
type RoleCreateParams struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Color string `json:"color,omitempty"`
Permissions uint16 `json:"permissions"`
}
RoleCreateParams creates a custom role. The name "owner" is reserved.
type RoleUpdateParams ¶
type RoleUpdateParams struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Color *string `json:"color,omitempty"`
Permissions *uint16 `json:"permissions,omitempty"`
}
RoleUpdateParams edits a custom role. Nil fields are left unchanged; edits propagate to every member holding the role.
type SMTPIMAPBulkParams ¶ added in v0.3.0
type SMTPIMAPBulkParams struct {
Accounts []SMTPIMAPParams `json:"accounts"`
}
SMTPIMAPBulkParams connects up to MaxSMTPIMAPBulkRows SMTP/IMAP mailboxes in one call.
type SMTPIMAPCredentialsParams ¶ added in v0.3.0
type SMTPIMAPCredentialsParams struct {
SMTP *MailboxCredentials `json:"smtp"`
IMAP *MailboxCredentials `json:"imap"`
}
SMTPIMAPCredentialsParams carries replacement credentials for an existing SMTP/IMAP mailbox. The address and display name never change on a reconnect.
type SMTPIMAPParams ¶
type SMTPIMAPParams struct {
Email string `json:"email"`
Name string `json:"name,omitempty"`
// SMTP is used for sending and IMAP for reading. Both are required.
SMTP *MailboxCredentials `json:"smtp"`
IMAP *MailboxCredentials `json:"imap"`
}
SMTPIMAPParams connects a mailbox by its own SMTP and IMAP credentials, for providers with no OAuth integration. The passwords are sealed server-side on receipt and never returned.
type SSORedirect ¶ added in v0.3.0
type SSORedirect struct {
// URL is the provider's authorization URL. Navigate the browser there.
URL string `json:"url"`
// Binding is the secret this client must keep (never in a URL) and hand
// to [AuthService.ExchangeSSO]. It ties the handoff to the browser that
// started the sign-in, so a forwarded handoff link cannot sign anyone in.
Binding string `json:"binding"`
}
SSORedirect is where to send the browser to start a provider sign-in, plus the binding secret that must come back at the exchange.
type ScheduleDeletionParams ¶
type ScheduleDeletionParams struct {
Confirmation string `json:"confirmation"`
Reason string `json:"reason,omitempty"`
}
ScheduleDeletionParams schedules a delayed hard delete. Confirmation must match the DangerZoneStatus.ConfirmationHint exactly.
type ScheduleWindows ¶
type ScheduleWindows [7][]TimeInterval
ScheduleWindows is a campaign's per-day sending schedule, indexed by weekday with Sunday at 0. An empty day means no sending that day. When any day is populated this supersedes the legacy Days/StartTime/EndTime fields.
func (ScheduleWindows) IsEmpty ¶
func (w ScheduleWindows) IsEmpty() bool
IsEmpty reports whether no day carries an interval, in which case the legacy day/time fields apply.
type ScheduledDeletion ¶
type ScheduledDeletion struct {
ID string `json:"id"`
ResourceType string `json:"resource_type"`
ResourceID string `json:"resource_id"`
OrganizationID *string `json:"organization_id,omitempty"`
RequestedByUserID string `json:"requested_by_user_id"`
Reason *string `json:"reason,omitempty"`
ScheduledAt time.Time `json:"scheduled_at"`
ExecuteAfter time.Time `json:"execute_after"`
GraceDays int `json:"grace_days"`
// Status is the deletion's lifecycle state: one of the DeletionStatus*
// constants.
Status string `json:"status"`
CancelledAt *time.Time `json:"cancelled_at,omitempty"` //nolint:misspell // wire value: the API sends "cancelled" here
CancelledByUserID *string `json:"cancelled_by_user_id,omitempty"` //nolint:misspell // wire value: the API sends "cancelled" here
CancelledReason *string `json:"cancelled_reason,omitempty"` //nolint:misspell // wire value: the API sends "cancelled" here
ExecutedAt *time.Time `json:"executed_at,omitempty"`
ExecutionError *string `json:"execution_error,omitempty"`
LastReminderAt *time.Time `json:"last_reminder_at,omitempty"`
}
ScheduledDeletion is a pending hard delete, cancelable until ExecuteAfter.
type ScheduledSend ¶
type ScheduledSend struct {
TaskID string `json:"task_id"`
ScheduledAt time.Time `json:"scheduled_at"`
CreatedAt time.Time `json:"created_at,omitempty"`
AccountID string `json:"account_id"`
AccountEmail string `json:"account_email,omitempty"`
AccountName string `json:"account_name,omitempty"`
To []string `json:"to,omitempty"`
CC []string `json:"cc,omitempty"`
BCC []string `json:"bcc,omitempty"`
Subject string `json:"subject"`
Snippet string `json:"snippet,omitempty"`
// ThreadID is the conversation the message will land in, when it was
// queued as a reply.
ThreadID string `json:"thread_id,omitempty"`
}
ScheduledSend is a queued outbound message that has not left yet.
type Segment ¶ added in v0.3.0
type Segment struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
CreatedBy *string `json:"created_by,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
// Color is a #rrggbb value, lower-cased by the server.
Color string `json:"color"`
Match SegmentMatch `json:"match"`
Conditions []SegmentCondition `json:"conditions"`
// ContactCount is the live membership size (conditions plus overrides).
ContactCount int `json:"contact_count"`
// IncludedCount is how many contacts are pinned in by hand.
IncludedCount int `json:"included_count"`
// ExcludedCount is how many contacts are pinned out by hand.
ExcludedCount int `json:"excluded_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Segment is a saved contact audience.
type SegmentAddToCampaignResult ¶ added in v0.3.0
type SegmentAddToCampaignResult struct {
CampaignID string `json:"campaign_id"`
// Added is how many leads were new to the campaign.
Added int `json:"added"`
// Members is the segment's membership size at enroll time; Members minus
// Added were already in the campaign.
Members int `json:"members"`
}
SegmentAddToCampaignResult reports a snapshot enrollment.
type SegmentCondition ¶ added in v0.3.0
type SegmentCondition struct {
Field string `json:"field"`
Operator SegmentOperator `json:"operator"`
// Value is the scalar operand, always sent as a string: "30" for a day
// count, "3" for a counter, "2026-01-15" for a date.
Value string `json:"value,omitempty"`
// Values is the list operand for in/not_in: enum options, or category,
// campaign or segment IDs.
Values []string `json:"values,omitempty"`
}
SegmentCondition is one predicate over a contact. Field names a filterable field (see SegmentService.Fields) or a custom field as SegmentCustomFieldPrefix plus its key; Operator picks the comparison. Scalar operators read Value, list operators read Values, and the valueless operators read neither. The server normalizes what it stores: dates become RFC 3339, numbers are canonicalized, and whichever of Value/Values the operator does not use is dropped.
type SegmentCreateParams ¶ added in v0.3.0
type SegmentCreateParams struct {
Name string `json:"name"`
Description *string `json:"description,omitempty"`
// Color is a #rrggbb value.
Color *string `json:"color,omitempty"`
Match *SegmentMatch `json:"match,omitempty"`
Conditions []SegmentCondition `json:"conditions,omitempty"`
}
SegmentCreateParams creates a segment. Name is required; everything else has a server default (no description, color #0284c7, match all, no conditions). A name already used by another segment is rejected with a 409.
type SegmentFieldKind ¶ added in v0.3.0
type SegmentFieldKind string
SegmentFieldKind groups filterable fields by the operators they accept. The per-kind operator sets are listed on the SegmentOperator constants.
const ( // SegmentFieldText fields (first_name, last_name, email, email_domain, // phone, company, custom.*) take the text operators; comparisons ignore // case. SegmentFieldText SegmentFieldKind = "text" // SegmentFieldEnum fields (source, verification_status, esp_provider) // take in/not_in with Values drawn from [SegmentFieldSpec.Options]. SegmentFieldEnum SegmentFieldKind = "enum" // SegmentFieldBool fields (subscribed, suppressed, is_catch_all) take // is_true/is_false and no value. SegmentFieldBool SegmentFieldKind = "bool" // SegmentFieldDate fields (created_at, updated_at, last_sent_at, // last_opened_at, last_clicked_at, last_replied_at) take within_days, // not_within_days, before, after, is_empty and is_not_empty. SegmentFieldDate SegmentFieldKind = "date" // SegmentFieldNumber fields (campaign_count, emails_sent, emails_opened, // emails_clicked, emails_replied, emails_bounced) take the comparison // operators with a whole-number Value. Engagement counters add up every // campaign the contact has been in; opens count human opens only. SegmentFieldNumber SegmentFieldKind = "number" // SegmentFieldCategory is the "category" field: in/not_in over category // IDs, plus is_empty/is_not_empty. SegmentFieldCategory SegmentFieldKind = "category" // SegmentFieldCampaign is the "campaign" field: in/not_in over campaign // IDs, plus is_empty/is_not_empty. SegmentFieldCampaign SegmentFieldKind = "campaign" // SegmentFieldSegment is the "segment" field: in/not_in over other // segment IDs. References nest at most five levels deep and may not form // a loop or point at the segment itself. SegmentFieldSegment SegmentFieldKind = "segment" )
type SegmentFieldSpec ¶ added in v0.3.0
type SegmentFieldSpec struct {
// Field is the value to put in [SegmentCondition.Field].
Field string `json:"field"`
// Label is the human-readable name, for a condition builder.
Label string `json:"label"`
// Group is the display group: "Contact", "Company", "Campaign
// activity", "Email engagement", "Segments" or "Custom field".
Group string `json:"group"`
Kind SegmentFieldKind `json:"kind"`
// Options lists the accepted Values of an enum field; nil otherwise.
Options []string `json:"options,omitempty"`
}
SegmentFieldSpec describes one field a condition may filter on. Kind determines the accepted operators and operand shape.
type SegmentMatch ¶ added in v0.3.0
type SegmentMatch string
SegmentMatch says how a segment combines its conditions.
const ( // SegmentMatchAll requires every condition to hold (AND). The default. SegmentMatchAll SegmentMatch = "all" // SegmentMatchAny requires at least one condition to hold (OR). SegmentMatchAny SegmentMatch = "any" )
type SegmentMemberMode ¶ added in v0.3.0
type SegmentMemberMode string
SegmentMemberMode is a manual override on one contact's membership. It takes precedence over the conditions: an included contact is a member whether or not it matches, an excluded one never is.
const ( // SegmentMemberInclude pins the contact into the segment. SegmentMemberInclude SegmentMemberMode = "include" // SegmentMemberExclude pins the contact out of the segment. SegmentMemberExclude SegmentMemberMode = "exclude" // SegmentMemberAuto clears the override so the conditions decide again. // It is only ever sent; a lookup never reports it. SegmentMemberAuto SegmentMemberMode = "auto" )
type SegmentOperator ¶ added in v0.3.0
type SegmentOperator string
SegmentOperator is the comparison a SegmentCondition applies. Which operators a field accepts depends on its SegmentFieldKind; the server rejects a mismatch with a 400 naming the offending condition.
const ( // SegmentOpEquals: text and number fields. SegmentOpEquals SegmentOperator = "equals" // SegmentOpNotEquals: text and number fields. SegmentOpNotEquals SegmentOperator = "not_equals" // SegmentOpContains: text fields, case-insensitive substring. SegmentOpContains SegmentOperator = "contains" // SegmentOpNotContains: text fields. SegmentOpNotContains SegmentOperator = "not_contains" // SegmentOpStartsWith: text fields. SegmentOpStartsWith SegmentOperator = "starts_with" // SegmentOpEndsWith: text fields. SegmentOpEndsWith SegmentOperator = "ends_with" // SegmentOpBefore: date fields; Value is YYYY-MM-DD or RFC 3339. SegmentOpBefore SegmentOperator = "before" // SegmentOpAfter: date fields; Value is YYYY-MM-DD or RFC 3339. SegmentOpAfter SegmentOperator = "after" // SegmentOpWithinDays: date fields; Value is a day count from 1 to 3650. SegmentOpWithinDays SegmentOperator = "within_days" // SegmentOpNotWithinDays: date fields; Value is a day count from 1 to // 3650. A contact with no date at all also matches. SegmentOpNotWithinDays SegmentOperator = "not_within_days" // SegmentOpGT: number fields. SegmentOpGT SegmentOperator = "gt" // SegmentOpGTE: number fields. SegmentOpGTE SegmentOperator = "gte" // SegmentOpLT: number fields. SegmentOpLT SegmentOperator = "lt" // SegmentOpLTE: number fields. SegmentOpLTE SegmentOperator = "lte" )
Scalar operators read SegmentCondition.Value.
const ( // SegmentOpIn: enum, category, campaign and segment fields. SegmentOpIn SegmentOperator = "in" // SegmentOpNotIn: enum, category, campaign and segment fields. SegmentOpNotIn SegmentOperator = "not_in" )
List operators read SegmentCondition.Values and need at least one entry.
const ( // SegmentOpIsEmpty: text, date, category and campaign fields. SegmentOpIsEmpty SegmentOperator = "is_empty" // SegmentOpIsNotEmpty: text, date, category and campaign fields. SegmentOpIsNotEmpty SegmentOperator = "is_not_empty" // SegmentOpIsTrue: bool fields. SegmentOpIsTrue SegmentOperator = "is_true" // SegmentOpIsFalse: bool fields. SegmentOpIsFalse SegmentOperator = "is_false" )
Valueless operators ignore both Value and Values.
type SegmentOverride ¶ added in v0.3.0
type SegmentOverride struct {
ContactID string `json:"contact_id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Company string `json:"company"`
// Mode is [SegmentMemberInclude] or [SegmentMemberExclude].
Mode SegmentMemberMode `json:"mode"`
// CreatedAt is when the override was set.
CreatedAt time.Time `json:"created_at"`
}
SegmentOverride is one contact pinned into or out of a segment by hand.
type SegmentPreviewParams ¶ added in v0.3.0
type SegmentPreviewParams struct {
// ID, when set, keeps that segment's manual overrides in the count, so
// editing an existing segment previews the number its members will see.
// It also lets the definition be checked for self-reference.
ID *string `json:"id,omitempty"`
// Match defaults to [SegmentMatchAll] when empty.
Match SegmentMatch `json:"match,omitempty"`
Conditions []SegmentCondition `json:"conditions"`
}
SegmentPreviewParams is an unsaved definition to count.
type SegmentPreviewResult ¶ added in v0.3.0
type SegmentPreviewResult struct {
// ContactCount is how many contacts the definition matches right now.
ContactCount int `json:"contact_count"`
}
SegmentPreviewResult is the answer to a preview.
type SegmentService ¶ added in v0.3.0
type SegmentService service
SegmentService manages segments: saved, reusable contact audiences. A segment is a list of conditions over contacts plus per-contact manual overrides. Membership is evaluated live on every read, so a segment never needs rebuilding and its counts are always current.
A contact is a member when it matches the conditions (per Segment.Match) or is manually included, and is not manually excluded. A segment with no conditions holds only its manual includes.
Segments read and write under the contact scopes, since a segment is a view over contacts. The one exception is SegmentService.AddToCampaign, which writes leads and therefore takes the campaign write scope.
Two ways to feed a campaign from a segment:
- SegmentService.AddToCampaign is a snapshot: it enrolls the members at the moment of the call and nothing more.
- Linking the segment to the campaign (PUT /campaigns/:id/segments, see CampaignService) is a live audience: members are enrolled immediately and contacts that later join the segment are enrolled as they appear, keeping a continuous campaign fed without further calls.
Contact search and export accept segment IDs to scope any contact query to a segment, and GET /contacts/:id/segments gives the contact-side view.
func (*SegmentService) AddToCampaign ¶ added in v0.3.0
func (s *SegmentService) AddToCampaign(ctx context.Context, id, campaignID string, opts ...RequestOption) (*SegmentAddToCampaignResult, *Response, error)
AddToCampaign enrolls every current member of the segment as a lead in the campaign. Contacts already in the campaign are skipped, each new lead gets a campaign_added activity, and a running campaign is woken so the leads are scheduled. Safe to retry.
This is a snapshot: contacts that join the segment later are not added until the call is repeated. For a live link that keeps enrolling members as they appear, link the segment to the campaign instead (PUT /campaigns/:id/segments via CampaignService).
Unlike the rest of the service this call takes the campaign write scope.
func (*SegmentService) Create ¶ added in v0.3.0
func (s *SegmentService) Create(ctx context.Context, params *SegmentCreateParams, opts ...RequestOption) (*Segment, *Response, error)
Create saves a segment and returns it with its initial live counts.
func (*SegmentService) Delete ¶ added in v0.3.0
func (s *SegmentService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete removes a segment and its overrides. Contacts are untouched. It fails with a 409 while another segment's conditions reference this one or a campaign has it linked as a live audience; detach it first.
func (*SegmentService) Fields ¶ added in v0.3.0
func (s *SegmentService) Fields(ctx context.Context, opts ...RequestOption) ([]SegmentFieldSpec, *Response, error)
Fields returns every field a condition may filter on: the built-in catalog followed by the workspace's custom fields, each as "custom.<key>" with kind text. Use it to validate conditions client-side or to drive a condition builder.
func (*SegmentService) Get ¶ added in v0.3.0
func (s *SegmentService) Get(ctx context.Context, id string, opts ...RequestOption) (*Segment, *Response, error)
Get returns one segment with live counts.
func (*SegmentService) List ¶ added in v0.3.0
func (s *SegmentService) List(ctx context.Context, opts ...RequestOption) ([]Segment, *Response, error)
List returns every segment in the organization with live counts. The endpoint is not paginated: a workspace holds at most 200 segments.
func (*SegmentService) MemberModes ¶ added in v0.3.0
func (s *SegmentService) MemberModes(ctx context.Context, id string, contactIDs []string, opts ...RequestOption) (map[string]SegmentMemberMode, *Response, error)
MemberModes reports the manual override on each of the given contacts, keyed by contact ID. Contacts with no override are absent from the map, so a missing key means the conditions alone decide. Up to SegmentMaxMemberBatch IDs per call.
func (*SegmentService) Overrides ¶ added in v0.3.0
func (s *SegmentService) Overrides(ctx context.Context, id string, opts ...RequestOption) ([]SegmentOverride, *Response, error)
Overrides lists every contact pinned into or out of the segment, includes first, newest first, capped at SegmentMaxOverrides.
func (*SegmentService) Preview ¶ added in v0.3.0
func (s *SegmentService) Preview(ctx context.Context, params *SegmentPreviewParams, opts ...RequestOption) (*SegmentPreviewResult, *Response, error)
Preview counts the contacts an unsaved definition matches, without creating anything. Invalid conditions come back as a 400 naming the condition, so it doubles as a validator.
func (*SegmentService) SetMembers ¶ added in v0.3.0
func (s *SegmentService) SetMembers(ctx context.Context, id string, contactIDs []string, mode SegmentMemberMode, opts ...RequestOption) (int, *Response, error)
SetMembers writes one manual override on a batch of contacts: SegmentMemberInclude pins them in, SegmentMemberExclude pins them out, SegmentMemberAuto clears any override so the conditions decide again. Up to SegmentMaxMemberBatch IDs per call; IDs outside the organization are ignored. It returns how many rows changed. Pinning in (or clearing an exclude) can admit new members, so linked campaigns are synced afterwards.
func (*SegmentService) Update ¶ added in v0.3.0
func (s *SegmentService) Update(ctx context.Context, id string, params *SegmentUpdateParams, opts ...RequestOption) (*Segment, *Response, error)
Update changes a segment's definition. Changing the conditions changes membership immediately, and any campaign the segment is linked to enrolls the new members on its next sync.
type SegmentUpdateParams ¶ added in v0.3.0
type SegmentUpdateParams struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Color *string `json:"color,omitempty"`
Match *SegmentMatch `json:"match,omitempty"`
// Conditions replaces the whole condition list. A nil slice leaves the
// conditions unchanged; an empty, non-nil slice ([]SegmentCondition{})
// removes them all, leaving a segment of manual includes only.
Conditions []SegmentCondition `json:"conditions"`
}
SegmentUpdateParams changes a segment. Nil fields are unchanged.
type SendEmailParams ¶
type SendEmailParams struct {
To []string `json:"to"`
CC []string `json:"cc,omitempty"`
BCC []string `json:"bcc,omitempty"`
Subject string `json:"subject"`
BodyHTML string `json:"body_html,omitempty"`
BodyPlain string `json:"body_plain,omitempty"`
// InReplyTo holds the RFC 5322 Message-IDs this message replies to.
InReplyTo []string `json:"in_reply_to,omitempty"`
// ThreadID continues an existing provider thread.
ThreadID string `json:"thread_id,omitempty"`
// SendMode is [SendModeInstant] (the default), [SendModeSmart] or
// [SendModeScheduled].
SendMode string `json:"send_mode,omitempty"`
// ScheduledAt is the send time, required when SendMode is
// [SendModeScheduled] and ignored otherwise. It must be in the future and
// within 29 days.
ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
}
SendEmailParams are the parameters for sending a one-off message from a mailbox.
type SendLifecycleState ¶ added in v0.3.0
type SendLifecycleState struct {
// State is [SendLifecycleActive], [SendLifecycleResting] or
// [SendLifecycleReserve].
State string `json:"state"`
// Since is when the mailbox entered State.
Since *time.Time `json:"since,omitempty"`
// Reason explains the transition, for example "held back by its owner".
Reason string `json:"reason,omitempty"`
}
SendLifecycleState is whether a mailbox is offered to campaign sending, separate from its warmup health and from which worker hosts it.
func (*SendLifecycleState) SendsCold ¶ added in v0.3.0
func (s *SendLifecycleState) SendsCold() bool
SendsCold reports whether the mailbox is in campaign rotation.
type SendResult ¶
type SendResult struct {
// TaskID identifies the queued send.
TaskID string `json:"task_id"`
// ScheduledAt is when the message will actually go out: immediately for
// [SendModeInstant], the next gap for [SendModeSmart], or the requested
// time for [SendModeScheduled].
ScheduledAt time.Time `json:"scheduled_at"`
SendMode string `json:"send_mode"`
}
SendResult is returned when a message has been accepted for delivery.
type SendTimeOptimizationSettings ¶
type SendTimeOptimizationSettings struct {
Enabled bool `json:"enabled"`
UseContactTimezone bool `json:"use_contact_timezone"`
DefaultContactTimezone string `json:"default_contact_timezone"`
// PreferredHours are local hours (0-23) to favor.
PreferredHours []int `json:"preferred_hours"`
WeekendWeightMultiplier float64 `json:"weekend_weight_multiplier"`
}
SendTimeOptimizationSettings holds each campaign email until the clock where the recipient reads mail reaches a preferred hour. It only ever delays a send, never brings one forward, and is off by default because turning it on changes when everything sends.
type SendingBehavior ¶ added in v0.3.0
type SendingBehavior struct {
EmailAccountID string `json:"email_account_id"`
// Enabled is off by default; a mailbox that has not opted in keeps its
// fixed daily cap and minimum gap exactly as before.
Enabled bool `json:"enabled"`
// DailyLimitMin and DailyLimitMax bound the day's cold-send target
// (defaults 30 to 45; 1 to 500).
DailyLimitMin int `json:"daily_limit_min"`
DailyLimitMax int `json:"daily_limit_max"`
// HourlyLimitMin and HourlyLimitMax bound the hourly ceiling (defaults 5
// to 9; 1 to 200), which stops the whole day landing in one burst.
HourlyLimitMin int `json:"hourly_limit_min"`
HourlyLimitMax int `json:"hourly_limit_max"`
// GapMinSeconds and GapMaxSeconds bound the delay between sends, drawn
// fresh for every send (defaults 90 to 420; 30 seconds to 24 hours).
GapMinSeconds int `json:"gap_min_seconds"`
GapMaxSeconds int `json:"gap_max_seconds"`
// WorkStartMin and WorkStartMax bound when the mailbox opens (defaults
// 09:03 to 09:27); WorkEndMin and WorkEndMax bound when it closes
// (defaults 17:18 to 17:56). The latest start must precede the earliest
// end.
WorkStartMin int `json:"work_start_min"`
WorkStartMax int `json:"work_start_max"`
WorkEndMin int `json:"work_end_min"`
WorkEndMax int `json:"work_end_max"`
// LunchEnabled (on by default) carves a quiet gap out of the day that
// starts between LunchEarliest and LunchLatest (defaults 12:00 to 13:30)
// and lasts LunchMinMinutes to LunchMaxMinutes (defaults 30 to 60, at most
// 240). The break must fit inside the shortest workday the ranges can
// produce.
LunchEnabled bool `json:"lunch_enabled"`
LunchEarliest int `json:"lunch_earliest"`
LunchLatest int `json:"lunch_latest"`
LunchMinMinutes int `json:"lunch_min_minutes"`
LunchMaxMinutes int `json:"lunch_max_minutes"`
// Weekdays is the Monday-indexed bitmask of sending days, cold and warmup
// alike (default [BehaviorWeekdays]). An enabled profile needs at least
// one day.
Weekdays int `json:"weekdays"`
// Timezone is a read-only echo of the mailbox's timezone.
Timezone string `json:"timezone,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
SendingBehavior is a mailbox's humanlike sending profile: the ranges a workday is rolled from, not the rolled values (see DailyPlan). Each local day the mailbox rolls one start, finish, break, daily target and hourly ceiling from these ranges and keeps to them, so it behaves like one person having one workday rather than a process re-deciding its schedule.
Every minute-of-day value is minutes since local midnight in the mailbox's own timezone. Behavior can only ever lower volume or delay a send: the rolled daily target is applied as a minimum against the mailbox and campaign caps, and the gap range replaces the mailbox's fixed minimum wait.
Disabled profiles are still stored, so the ranges can be tuned before switching the profile on. A mailbox that has never been configured reads back the defaults.
type SendingBehaviorUpdateParams ¶ added in v0.3.0
type SendingBehaviorUpdateParams struct {
Enabled *bool `json:"enabled,omitempty"`
DailyLimitMin *int `json:"daily_limit_min,omitempty"`
DailyLimitMax *int `json:"daily_limit_max,omitempty"`
HourlyLimitMin *int `json:"hourly_limit_min,omitempty"`
HourlyLimitMax *int `json:"hourly_limit_max,omitempty"`
GapMinSeconds *int `json:"gap_min_seconds,omitempty"`
GapMaxSeconds *int `json:"gap_max_seconds,omitempty"`
WorkStartMin *int `json:"work_start_min,omitempty"`
WorkStartMax *int `json:"work_start_max,omitempty"`
WorkEndMin *int `json:"work_end_min,omitempty"`
WorkEndMax *int `json:"work_end_max,omitempty"`
LunchEnabled *bool `json:"lunch_enabled,omitempty"`
LunchEarliest *int `json:"lunch_earliest,omitempty"`
LunchLatest *int `json:"lunch_latest,omitempty"`
LunchMinMinutes *int `json:"lunch_min_minutes,omitempty"`
LunchMaxMinutes *int `json:"lunch_max_minutes,omitempty"`
Weekdays *int `json:"weekdays,omitempty"`
}
SendingBehaviorUpdateParams is a partial update to a SendingBehavior. Nil fields keep their stored value, so Enabled can be toggled without resending every range. A range that breaks a cross-field rule is rejected with a 400 naming the field. Editing the ranges does not change today's rolled plan; the new ranges take effect on the next roll.
type Session ¶
type Session struct {
AccessToken string `json:"access_token"`
AccessTokenExpiresAt time.Time `json:"access_token_expires_at"`
RefreshToken string `json:"refresh_token"`
RefreshTokenExpiresAt time.Time `json:"refresh_token_expires_at"`
// TwoFARequired is true when the account has two-factor enabled. The token
// fields are then empty; finish with [AuthService.VerifyTwoFA] using
// PendingToken.
TwoFARequired bool `json:"two_fa_required,omitempty"`
// PendingToken is the single-use handle for the 2FA step.
PendingToken string `json:"pending_token,omitempty"`
// ExpiresIn is how long PendingToken remains valid, in seconds.
ExpiresIn int `json:"expires_in,omitempty"`
}
Session is a signed-in session's token pair.
type SetupParams ¶ added in v0.3.0
type SetupParams struct {
Token string `json:"token"`
Email string `json:"email"`
Password string `json:"password"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
SetupParams claims a fresh self-hosted instance. Token is the one-time setup token printed at first boot (or by warmblyctl setup-link); the rest becomes the owner account.
type SkillCreateParams ¶
type SkillCreateParams struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Content string `json:"content,omitempty"`
// Enabled defaults to true when nil.
Enabled *bool `json:"enabled,omitempty"`
}
SkillCreateParams creates a skill. Name is required.
type SkillService ¶
type SkillService service
SkillService manages AI skills: workspace playbooks folded into every AI writing surface, on top of the voice profile on Organization.
An enabled skill applies everywhere the assistant writes, so keep them short and behavioral — "never open with 'I hope this finds you well'" — rather than piling in per-campaign detail.
func (*SkillService) Create ¶
func (s *SkillService) Create(ctx context.Context, params *SkillCreateParams, opts ...RequestOption) (*AISkill, *Response, error)
Create adds an AI skill.
func (*SkillService) Delete ¶
func (s *SkillService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete removes an AI skill.
func (*SkillService) List ¶
func (s *SkillService) List(ctx context.Context, opts ...RequestOption) ([]AISkill, *Response, error)
List returns the workspace's AI skills.
func (*SkillService) Update ¶
func (s *SkillService) Update(ctx context.Context, id string, params *SkillUpdateParams, opts ...RequestOption) (*AISkill, *Response, error)
Update modifies an AI skill.
type SkillUpdateParams ¶
type SkillUpdateParams struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Content *string `json:"content,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
SkillUpdateParams updates a skill. Nil fields are left unchanged.
type Spreadsheet ¶
type Spreadsheet struct {
SheetID string `json:"sheet_id"`
Title string `json:"title"`
Tabs []SpreadsheetTab `json:"tabs"`
}
Spreadsheet is a workbook's title and its tabs.
type SpreadsheetTab ¶
SpreadsheetTab is one tab in a workbook.
type StageCreateParams ¶
StageCreateParams creates one pipeline stage.
type StageUpdateParams ¶
type StageUpdateParams struct {
Name *string `json:"name,omitempty"`
Color *string `json:"color,omitempty"`
}
StageUpdateParams updates a stage. Nil fields are left unchanged.
type Step ¶
type Step struct {
ID string `json:"id"`
Name string `json:"name"`
Subject string `json:"subject"`
BodyPlain string `json:"body_plain"`
BodyHTML string `json:"body_html"`
// BodySync keeps the plain-text body derived from the HTML body.
BodySync bool `json:"body_sync"`
// BodyCode reports whether the HTML body is edited as raw markup.
BodyCode bool `json:"body_code"`
// WaitAfter is the delay in minutes before the next step runs.
WaitAfter int `json:"wait_after"`
// Position is the step's zero-based index in the sequence. It orders the
// canvas and picks the entry step; it never advances a contact by itself.
Position int `json:"position"`
// X and Y are the step's coordinates on the sequence canvas. They are
// written only through [CampaignService.UpdateStepLayout].
X float64 `json:"x"`
Y float64 `json:"y"`
// Conditions is the step's routing: the connections out of it, evaluated
// against the contact's engagement to pick the next step. Routing follows
// connections only, so a step with an empty tree (no branches) has no
// outgoing path and the contact's flow ends there; a plain "go there next"
// link is a branch with no conditions. It is left as raw JSON because the
// branch grammar evolves independently of this SDK.
Conditions json.RawMessage `json:"conditions,omitempty"`
// Kind is [StepKindEmail], [StepKindAction] or [StepKindWait].
Kind string `json:"kind"`
// Action is the typed configuration for a non-email node, as raw JSON. It
// is an empty object for email steps.
Action json.RawMessage `json:"action,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
}
Step is a single step in a campaign's sequence.
type StepAnalytics ¶
type StepAnalytics struct {
StepID string `json:"step_id"`
Name string `json:"name"`
Position int `json:"position"`
EmailsSent int64 `json:"emails_sent"`
Opens int64 `json:"opens"`
Clicks int64 `json:"clicks"`
Replies int64 `json:"replies"`
Bounces int64 `json:"bounces"`
}
StepAnalytics is one sequence step's engagement.
type StepInput ¶
type StepInput struct {
Name string `json:"name,omitempty"`
Subject string `json:"subject,omitempty"`
BodyPlain string `json:"body_plain,omitempty"`
BodyHTML string `json:"body_html,omitempty"`
BodySync *bool `json:"body_sync,omitempty"`
BodyCode *bool `json:"body_code,omitempty"`
WaitAfter *int `json:"wait_after,omitempty"`
}
StepInput is one step seeded during campaign creation.
type StepPosition ¶
StepPosition is one step's coordinates on the sequence canvas.
type StepUpdateParams ¶
type StepUpdateParams struct {
Name *string `json:"name,omitempty"`
Subject *string `json:"subject,omitempty"`
BodyPlain *string `json:"body_plain,omitempty"`
BodyHTML *string `json:"body_html,omitempty"`
BodySync *bool `json:"body_sync,omitempty"`
BodyCode *bool `json:"body_code,omitempty"`
WaitAfter *int `json:"wait_after,omitempty"`
// Conditions replaces the step's outgoing connections when non-nil. Send
// an empty object to remove them all, after which the contact's flow ends
// at this step.
Conditions json.RawMessage `json:"conditions,omitempty"`
// Kind and Action switch the node between an email and an action or wait.
// A one-time campaign refuses a second email step.
Kind *string `json:"kind,omitempty"`
Action json.RawMessage `json:"action,omitempty"`
}
StepUpdateParams updates a campaign step. Nil fields are left unchanged.
type StorageUsage ¶ added in v0.3.0
type StorageUsage struct {
UsedBytes int64 `json:"used_bytes"`
LimitBytes int64 `json:"limit_bytes"`
OverQuota bool `json:"over_quota"`
}
StorageUsage is attachment storage used against the workspace's quota. A workspace that dropped to a smaller plan can be over quota with no upload refused yet, which is what OverQuota reports.
type Subscription ¶
type Subscription struct {
ID string `json:"id"`
UserID string `json:"user_id"`
OrganizationID string `json:"organization_id"`
PlanID string `json:"plan_id"`
StripeCustomerID string `json:"stripe_customer_id,omitempty"`
StripeSubscriptionID *string `json:"stripe_subscription_id,omitempty"`
StripePriceID *string `json:"stripe_price_id,omitempty"`
// Status is the lifecycle state, for example "active", "trialing" or
// "canceled".
Status string `json:"status"`
CurrentPeriodStart *time.Time `json:"current_period_start,omitempty"`
CurrentPeriodEnd *time.Time `json:"current_period_end,omitempty"`
// CancelAtPeriodEnd is true when the subscription is set to lapse rather
// than renew.
CancelAtPeriodEnd bool `json:"cancel_at_period_end"`
CanceledAt *time.Time `json:"canceled_at,omitempty"`
TrialStart *time.Time `json:"trial_start,omitempty"`
TrialEnd *time.Time `json:"trial_end,omitempty"`
// FreeTrialStartedAt and FreeTrialEndsAt are Warmbly's own free trial,
// distinct from a provider-side trial.
FreeTrialStartedAt *time.Time `json:"free_trial_started_at,omitempty"`
FreeTrialEndsAt *time.Time `json:"free_trial_ends_at,omitempty"`
// IsEnterprise marks a subscription negotiated outside the plan catalog.
IsEnterprise bool `json:"is_enterprise"`
// Plan is the plan this subscription is on, joined in by the API so a
// caller does not have to look it up in [MetaService.Plans].
Plan *Plan `json:"plan,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
Subscription is the workspace's current plan subscription.
type SubscriptionStatus ¶
type SubscriptionStatus struct {
HasSubscription bool `json:"has_subscription"`
IsInFreeTrial bool `json:"is_in_free_trial"`
IsFreeTrialExpired bool `json:"is_free_trial_expired"`
IsPaidSubscriber bool `json:"is_paid_subscriber"`
// DailyEmailLimit is the send cap the server enforces: an approved limit
// increase, else the plan's, else the trial's.
DailyEmailLimit int `json:"daily_email_limit"`
Plan *Plan `json:"plan,omitempty"`
}
SubscriptionStatus is the plan-gate view: what the workspace is entitled to.
type SubscriptionWithLimits ¶ added in v0.3.0
type SubscriptionWithLimits struct {
Subscription
RateLimits *RealtimeRateLimits `json:"rate_limits,omitempty"`
}
SubscriptionWithLimits is the subscription together with the realtime gateway ceilings its plan carries.
type SuppressedRecipient ¶ added in v0.3.0
type SuppressedRecipient struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
// Email is the suppressed address, or the bare domain when Kind is
// [SuppressionKindDomain]. Always lower-case.
Email string `json:"email"`
Kind SuppressionKind `json:"kind"`
Reason string `json:"reason"`
Source SuppressionSource `json:"source"`
// CampaignID is the campaign whose send produced an automatic entry;
// nil for manual and import entries.
CampaignID *string `json:"campaign_id,omitempty"`
// ExpiresAt, when set, is when the entry stops applying. Expired entries
// are never listed. Entries added through the API do not expire.
ExpiresAt *time.Time `json:"expires_at,omitempty"`
// Metadata carries provenance, such as "added_by" (the user who added a
// manual entry) or "via" for an unsubscribe.
Metadata map[string]any `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
SuppressedRecipient is one entry on the suppression list.
type SuppressionAddParams ¶ added in v0.3.0
type SuppressionAddParams struct {
// Entries holds up to [SuppressionMaxEntries] values. Duplicates within
// the batch are collapsed.
Entries []SuppressionEntry `json:"entries"`
// Reason applies to every entry that does not carry its own. When both
// are empty the server records a generic one.
Reason string `json:"reason,omitempty"`
}
SuppressionAddParams adds addresses and domains to the list.
type SuppressionAddResult ¶ added in v0.3.0
type SuppressionAddResult struct {
// Added is how many entries were written, counting values already on
// the list that were updated in place.
Added int `json:"added"`
// Skipped lists the values, as sent, that were neither a valid address
// nor a valid domain. They do not fail the request.
Skipped []string `json:"skipped"`
}
SuppressionAddResult reports what an Add did.
type SuppressionEntry ¶ added in v0.3.0
type SuppressionEntry struct {
// Value is an address ("dana@acme.com") or a domain ("acme.com" or
// "@acme.com"). Anything with an "@" after a leading one is stripped is
// treated as an address; a bare host is a domain. The server decides
// the kind: there is no way to force a value to one or the other.
Value string `json:"value"`
// Reason overrides [SuppressionAddParams.Reason] for this entry.
Reason string `json:"reason,omitempty"`
}
SuppressionEntry is one value to suppress.
type SuppressionKind ¶ added in v0.3.0
type SuppressionKind string
SuppressionKind says what a suppression entry matches.
const ( // SuppressionKindEmail matches one address. SuppressionKindEmail SuppressionKind = "email" // SuppressionKindDomain matches every address at a domain; the entry's // Email holds the bare host. SuppressionKindDomain SuppressionKind = "domain" )
type SuppressionListParams ¶ added in v0.3.0
type SuppressionListParams struct {
ListOptions
// Query is a case-insensitive substring filter on the address or
// domain.
Query string `json:"-"`
}
SuppressionListParams filters and pages the suppression list. Pages are newest first; Limit is capped at 200 and defaults to 50.
type SuppressionService ¶ added in v0.3.0
type SuppressionService service
SuppressionService manages the workspace suppression list: every address and domain that no campaign will email, whatever put it there. The list is checked before every campaign send.
Entries arrive two ways. Warmbly adds them automatically on a hard bounce, a spam complaint or an unsubscribe (sources bounce, complaint, unsubscribe); you add them by hand with SuppressionService.Add (sources manual and import). Lifting an entry with SuppressionService.Delete lets campaigns email the address, or every address at the domain, again.
Adding an address also switches off the matching contact's subscribed flag, and removing it switches the flag back on, so the list and the contact never disagree. Reads take the contact read scope, writes the contact write scope.
func (*SuppressionService) Add ¶ added in v0.3.0
func (s *SuppressionService) Add(ctx context.Context, params *SuppressionAddParams, opts ...RequestOption) (*SuppressionAddResult, *Response, error)
Add puts addresses and domains on the list. A single entry is recorded with source manual, two or more with source import. Values already on the list are updated in place rather than rejected, so the call is safe to repeat; values that are neither an address nor a domain come back in SuppressionAddResult.Skipped. The batch is written in one transaction. Adding an address also unsubscribes the matching contact.
func (*SuppressionService) Delete ¶ added in v0.3.0
func (s *SuppressionService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete lifts one entry so campaigns can email the address (or every address at the domain) again. Removing an address entry also restores the matching contact's subscribed flag. The removal is audited with the entry's value, kind and source, since lifting an opt-out the recipient made themselves is what a compliance review looks for. Returns a 404 when the entry is not in this organization.
func (*SuppressionService) List ¶ added in v0.3.0
func (s *SuppressionService) List(ctx context.Context, params *SuppressionListParams, opts ...RequestOption) (*Page[SuppressedRecipient], error)
List pages the suppression list, newest first. Expired entries are omitted. Pass nil for the first page with defaults.
type SuppressionSource ¶ added in v0.3.0
type SuppressionSource string
SuppressionSource records what put an entry on the list.
const ( // SuppressionSourceBounce: a permanent (5.x.x) delivery failure. SuppressionSourceBounce SuppressionSource = "bounce" // SuppressionSourceComplaint: the recipient marked a send as spam. SuppressionSourceComplaint SuppressionSource = "complaint" // SuppressionSourceUnsubscribe: the recipient opted out, by link, reply // keyword or List-Unsubscribe header. SuppressionSourceUnsubscribe SuppressionSource = "unsubscribe" // SuppressionSourceManual: added by hand, one entry at a time. SuppressionSourceManual SuppressionSource = "manual" // SuppressionSourceImport: added by hand as a batch of two or more. SuppressionSourceImport SuppressionSource = "import" )
type SyncRun ¶
type SyncRun struct {
ID string `json:"id"`
ConnectionID string `json:"connection_id"`
OrganizationID string `json:"organization_id,omitempty"`
// Kind is what ran, for example "push" or "pull".
Kind string `json:"kind"`
// Status is the outcome, for example "success" or "error".
Status string `json:"status"`
Detail string `json:"detail,omitempty"`
RecordsProcessed int `json:"records_processed"`
StartedAt time.Time `json:"started_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
}
SyncRun is one execution of a connection's sync.
type TaskReliabilitySettings ¶
type TaskReliabilitySettings struct {
Enabled bool `json:"enabled"`
DLQEnabled bool `json:"dlq_enabled"`
MaxAttempts int `json:"max_attempts"`
ExecutionWindowSeconds int `json:"execution_window_seconds"`
}
TaskReliabilitySettings tunes send-task retries and the dead-letter queue.
type TaskSearchParams ¶
type TaskSearchParams struct {
ListOptions
// Query matches the task title.
Query string `json:"query,omitempty"`
// Statuses matches any of the TaskStatus* constants, Priorities any of the
// TaskPriority* constants, and Types any [CRMTaskType] name.
Statuses []string `json:"statuses,omitempty"`
Priorities []string `json:"priorities,omitempty"`
Types []string `json:"types,omitempty"`
// AssignedTo matches any of the given assignee user ids. TeamIDs matches
// tasks assigned to any of those teams, or whose assignee belongs to one.
AssignedTo []string `json:"assigned_to,omitempty"`
TeamIDs []string `json:"team_ids,omitempty"`
ContactID *string `json:"contact_id,omitempty"`
DealID *string `json:"deal_id,omitempty"`
DueAfter *time.Time `json:"due_after,omitempty"`
DueBefore *time.Time `json:"due_before,omitempty"`
// Overdue matches tasks past their due date that are neither completed nor
// canceled.
Overdue bool `json:"overdue,omitempty"`
// SortBy is "created_at", "due_date", "priority", "title" or "updated_at".
// Reverse switches to ascending; the default is descending.
SortBy string `json:"sort_by,omitempty"`
Reverse bool `json:"reverse,omitempty"`
}
TaskSearchParams is the faceted filter shared by CRMService.SearchTasks and CRMService.TasksSummary. Every facet is optional; slice facets match any of their values.
type TaskService ¶
type TaskService service
TaskService inspects and replays the send-task dead-letter queue: work that exhausted its retries and parked instead of being dropped.
A replay re-dispatches real mail, so it needs the send permission.
func (*TaskService) DeadLetters ¶
func (s *TaskService) DeadLetters(ctx context.Context, params *DeadLetterListParams, opts ...RequestOption) ([]DeadLetter, *Response, error)
DeadLetters returns parked tasks.
func (*TaskService) Replay ¶
func (s *TaskService) Replay(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Replay re-dispatches a parked task. This sends real mail.
type TaskTypeCreateParams ¶
type TaskTypeCreateParams struct {
Name string `json:"name"`
Color string `json:"color,omitempty"`
}
TaskTypeCreateParams creates a task type.
type TaskTypeUpdateParams ¶
type TaskTypeUpdateParams struct {
Name *string `json:"name,omitempty"`
Color *string `json:"color,omitempty"`
Position *int `json:"position,omitempty"`
}
TaskTypeUpdateParams updates a task type. Nil fields are left unchanged.
type TasksSummary ¶
type TasksSummary struct {
Total int64 `json:"total"`
PendingCount int64 `json:"pending_count"`
InProgress int64 `json:"in_progress_count"`
CompletedCount int64 `json:"completed_count"`
CancelledCount int64 `json:"cancelled_count"` //nolint:misspell // wire value: the API sends "cancelled" here
OverdueCount int64 `json:"overdue_count"`
HighPriority int64 `json:"high_priority_count"`
}
TasksSummary aggregates every task matching a TaskSearchParams.
type Team ¶
type Team struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Color string `json:"color"`
Members []TeamMember `json:"members"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Team is a named group of workspace members.
type TeamCreateParams ¶
TeamCreateParams creates a team.
type TeamMember ¶
type TeamMember struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Name string `json:"name"`
AddedAt time.Time `json:"added_at"`
}
TeamMember is one member of a team.
type TeamService ¶
type TeamService service
TeamService groups existing workspace members into named teams, which CRM tasks and deals can be assigned to instead of a single person.
func (*TeamService) AddMember ¶
func (s *TeamService) AddMember(ctx context.Context, id, userID string, opts ...RequestOption) (*Team, *Response, error)
AddMember adds an existing workspace member to a team.
func (*TeamService) Create ¶
func (s *TeamService) Create(ctx context.Context, params *TeamCreateParams, opts ...RequestOption) (*Team, *Response, error)
Create creates a team.
func (*TeamService) Delete ¶
func (s *TeamService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete removes a team. Its members keep their workspace membership.
func (*TeamService) Get ¶
func (s *TeamService) Get(ctx context.Context, id string, opts ...RequestOption) (*Team, *Response, error)
Get retrieves a single team.
func (*TeamService) List ¶
func (s *TeamService) List(ctx context.Context, opts ...RequestOption) ([]Team, *Response, error)
List returns the workspace's teams with their members.
func (*TeamService) RemoveMember ¶
func (s *TeamService) RemoveMember(ctx context.Context, id, userID string, opts ...RequestOption) (*Response, error)
RemoveMember removes someone from a team.
func (*TeamService) Update ¶
func (s *TeamService) Update(ctx context.Context, id string, params *TeamUpdateParams, opts ...RequestOption) (*Team, *Response, error)
Update renames or recolors a team.
type TeamUpdateParams ¶
type TeamUpdateParams struct {
Name *string `json:"name,omitempty"`
Color *string `json:"color,omitempty"`
}
TeamUpdateParams renames or recolors a team.
type Template ¶
type Template struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
Name string `json:"name"`
Subject string `json:"subject"`
BodyHTML string `json:"body_html"`
BodyPlain string `json:"body_plain"`
// Position is the template's place in the organization's ordered list.
Position int `json:"position"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Template is a reusable message template as returned by the API.
type TemplateCreateParams ¶
type TemplateCreateParams struct {
Name string `json:"name"`
Subject string `json:"subject,omitempty"`
BodyHTML string `json:"body_html,omitempty"`
BodyPlain string `json:"body_plain,omitempty"`
}
TemplateCreateParams creates a template. Only Name is required.
type TemplateField ¶ added in v0.3.0
TemplateField is one templated key/value pair in an action config. Value is a Go template rendered against the event data, so "{{.data.company}}" reads a form answer and "{{.first_name}}" a contact field.
type TemplateIssue ¶
type TemplateIssue struct {
// Severity is [TemplateIssueWarn] or [TemplateIssueHigh].
Severity string `json:"severity"`
// Code is the stable identifier for the rule that fired.
Code string `json:"code"`
Message string `json:"message"`
}
TemplateIssue is one problem found while scoring copy.
type TemplatePreviewAttachment ¶ added in v0.3.0
type TemplatePreviewAttachment struct {
ID string `json:"id"`
Filename string `json:"filename"`
Size int64 `json:"size"`
MimeType string `json:"mime_type"`
}
TemplatePreviewAttachment is one attachment a previewed send would carry.
type TemplatePreviewFrom ¶ added in v0.3.0
TemplatePreviewFrom is the sender line of a rendered preview.
type TemplatePreviewInput ¶
type TemplatePreviewInput struct {
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Email string `json:"email,omitempty"`
Company string `json:"company,omitempty"`
Phone string `json:"phone,omitempty"`
CustomFields map[string]string `json:"custom_fields,omitempty"`
}
TemplatePreviewInput is the sample contact merge tags are resolved against.
type TemplatePreviewParams ¶
type TemplatePreviewParams struct {
Subject string `json:"subject,omitempty"`
BodyHTML string `json:"body_html,omitempty"`
BodyPlain string `json:"body_plain,omitempty"`
// Contact overrides individual fields of the contact rendered for (the
// sample one, or the one named by ContactID).
Contact *TemplatePreviewInput `json:"contact,omitempty"`
// ContactID renders for a real contact of the organization. It requires
// contact read access on top of the campaign permission.
ContactID string `json:"contact_id,omitempty"`
// CampaignID applies the campaign's opt-out footer and plain-text rule and
// lists its campaign-wide attachments in the result.
CampaignID string `json:"campaign_id,omitempty"`
// AccountID applies that mailbox's signature and fills
// [TemplatePreviewResult.From].
AccountID string `json:"account_id,omitempty"`
// StepID adds that step's own attachments to the campaign-wide ones. It
// only means something with CampaignID.
StepID string `json:"step_id,omitempty"`
}
TemplatePreviewParams renders campaign copy exactly as the send path would, so merge tags can be checked without sending anything. With no context it renders against a built-in sample contact; CampaignID, AccountID, ContactID and StepID add the pieces of a real send.
type TemplatePreviewResult ¶
type TemplatePreviewResult struct {
Subject string `json:"subject"`
BodyHTML string `json:"body_html"`
BodyPlain string `json:"body_plain"`
// Errors are template syntax problems. They block sending.
Errors []string `json:"errors,omitempty"`
// Unresolved lists merge tags with no value on the contact.
Unresolved []string `json:"unresolved,omitempty"`
// From is the sender as the recipient will see it, when AccountID was
// given.
From *TemplatePreviewFrom `json:"from,omitempty"`
// Attachments are the files the send would carry, metadata only.
Attachments []TemplatePreviewAttachment `json:"attachments,omitempty"`
}
TemplatePreviewResult is the rendered copy plus anything that failed to resolve. Tracking rewrites are left out; everything else the send path adds (signature, opt-out footer, sender, attachments) is included when the request named the campaign and mailbox.
type TemplateRenderResult ¶
type TemplateRenderResult struct {
Subject string `json:"subject"`
BodyHTML string `json:"body_html"`
BodyPlain string `json:"body_plain"`
}
TemplateRenderResult is a template rendered against a set of variables.
type TemplateScore ¶
type TemplateScore struct {
Score int `json:"score"`
Issues []TemplateIssue `json:"issues"`
}
TemplateScore rates copy for spam risk before it is ever sent. Score runs 0 to 100, higher being safer.
type TemplateScoreParams ¶
type TemplateScoreParams struct {
Subject string `json:"subject,omitempty"`
BodyHTML string `json:"body_html,omitempty"`
BodyPlain string `json:"body_plain,omitempty"`
}
TemplateScoreParams is the copy to score. Pass whichever parts exist.
type TemplateService ¶
type TemplateService service
TemplateService manages the organization's reply templates: reusable subject and body snippets that can be rendered into a campaign step or a one-off reply. Templates are ordered, and the order is editable.
func (*TemplateService) Create ¶
func (s *TemplateService) Create(ctx context.Context, params *TemplateCreateParams, opts ...RequestOption) (*Template, *Response, error)
Create creates a new template, appended to the end of the list.
func (*TemplateService) Delete ¶
func (s *TemplateService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete permanently deletes a template.
func (*TemplateService) Duplicate ¶
func (s *TemplateService) Duplicate(ctx context.Context, id string, opts ...RequestOption) (*Template, *Response, error)
Duplicate copies a template, appending the copy to the end of the list.
func (*TemplateService) Get ¶
func (s *TemplateService) Get(ctx context.Context, id string, opts ...RequestOption) (*Template, *Response, error)
Get retrieves a single template by ID.
func (*TemplateService) List ¶
func (s *TemplateService) List(ctx context.Context, query string, opts ...RequestOption) ([]Template, *Response, error)
List returns the organization's templates in their configured order. Query is an optional case-insensitive search over name and subject.
func (*TemplateService) Render ¶
func (s *TemplateService) Render(ctx context.Context, id string, variables map[string]string, opts ...RequestOption) (*TemplateRenderResult, *Response, error)
Render fills a template's merge tags from variables and returns the result. Nothing is sent.
func (*TemplateService) Reorder ¶
func (s *TemplateService) Reorder(ctx context.Context, ids []string, opts ...RequestOption) ([]Template, *Response, error)
Reorder repositions the given templates in the listed order and returns the full reordered list. Templates not in ids keep their positions.
func (*TemplateService) Score ¶
func (s *TemplateService) Score(ctx context.Context, params *TemplateScoreParams, opts ...RequestOption) (*TemplateScore, *Response, error)
Score rates arbitrary copy for spam risk. It works on any subject and body, not just a stored template.
func (*TemplateService) Update ¶
func (s *TemplateService) Update(ctx context.Context, id string, params *TemplateUpdateParams, opts ...RequestOption) (*Template, *Response, error)
Update modifies an existing template.
type TemplateUpdateParams ¶
type TemplateUpdateParams struct {
Name *string `json:"name,omitempty"`
Subject *string `json:"subject,omitempty"`
BodyHTML *string `json:"body_html,omitempty"`
BodyPlain *string `json:"body_plain,omitempty"`
}
TemplateUpdateParams updates a template. Nil fields are left unchanged.
type TestEmailParams ¶
type TestEmailParams struct {
// AccountID is the mailbox the test is sent from.
AccountID string `json:"account_id"`
Recipient string `json:"recipient"`
// StepID selects which step to render; the first step is used when empty.
StepID string `json:"step_id,omitempty"`
// ContactID renders the copy for a real contact of the organization
// instead of the built-in sample one. It requires contact read access on
// top of the campaign permission.
ContactID string `json:"contact_id,omitempty"`
}
TestEmailParams sends a rendered preview of a campaign step to one address. The test carries the step's attachments, the mailbox signature and the opt-out footer, rendered from what is saved (not unsaved edits). Opens and clicks on a test are not tracked and its opt-out link names nobody.
type TestEmailResult ¶
type TestEmailResult struct {
Message string `json:"message"`
Recipient string `json:"recipient"`
Subject string `json:"subject"`
AccountID string `json:"account_id"`
// StepID is the step that was rendered.
StepID string `json:"step_id"`
// ContactID echoes the contact rendered for, when one was given.
ContactID string `json:"contact_id,omitempty"`
}
TestEmailResult confirms a test send.
type TimeInterval ¶
TimeInterval is one sending window inside a day, in minutes since local midnight. End is exclusive and must be greater than Start and at most 1440.
type TimelineEvent ¶
type TimelineEvent struct {
// Type is one of the Timeline* constants.
Type string `json:"type"`
At time.Time `json:"at"`
EmailAccountID *string `json:"email_account_id,omitempty"`
EmailAccountEmail *string `json:"email_account_email,omitempty"`
EmailAccountName *string `json:"email_account_name,omitempty"`
CampaignID *string `json:"campaign_id,omitempty"`
CampaignName *string `json:"campaign_name,omitempty"`
StepID *string `json:"step_id,omitempty"`
StepName *string `json:"step_name,omitempty"`
TaskID *string `json:"task_id,omitempty"`
// Subject is the email subject, or the page title for [TimelinePageHit].
Subject *string `json:"subject,omitempty"`
Reason *string `json:"reason,omitempty"`
// Source is the suppression source on [TimelineSuppressed] events and the
// first-touch ContactSource* value on [TimelineContactCreated] events.
Source *string `json:"source,omitempty"`
Provider *string `json:"provider,omitempty"`
// Intent is the reply-intent classification, for example "positive".
Intent *string `json:"intent,omitempty"`
// Content is the note body for [TimelineNote] events.
Content *string `json:"content,omitempty"`
// ScheduledFor, JoinURL and MeetingState are set on meeting events.
ScheduledFor *time.Time `json:"scheduled_for,omitempty"`
JoinURL *string `json:"join_url,omitempty"`
MeetingState *string `json:"meeting_state,omitempty"`
// CategoryID and CategoryTitle are set on category lifecycle events;
// SourceDetail on [TimelineContactCreated] (the file, campaign, sheet,
// form, automation or API key name).
CategoryID *string `json:"category_id,omitempty"`
CategoryTitle *string `json:"category_title,omitempty"`
SourceDetail *string `json:"source_detail,omitempty"`
// FormID and FormName are set on [TimelineFormSubmitted] events.
FormID *string `json:"form_id,omitempty"`
FormName *string `json:"form_name,omitempty"`
// PageHit is the full page view behind a [TimelinePageHit] event.
PageHit *ContactPageHit `json:"page_hit,omitempty"`
// Machine is set on opens and clicks: true when an automated fetcher did
// it rather than the person. MachineReason is one of the MachineReason*
// constants when the event was logged individually. Automated clicks stay
// on the feed for the record but never count the step as clicked.
Machine *bool `json:"machine,omitempty"`
MachineReason *string `json:"machine_reason,omitempty"`
// Link is the exact link behind an [TimelineEmailClicked] event.
Link *ContactLinkClick `json:"link,omitempty"`
// Origin is the mail client, device and rough location of an open or
// click, when the event was logged individually. Opens appear once per
// event, so a contact who opened from two devices has two rows.
Origin *EngagementOrigin `json:"origin,omitempty"`
// UserID is the author of a note or the member behind a lifecycle event.
UserID *string `json:"user_id,omitempty"`
}
TimelineEvent is one entry in a contact's merged activity feed. Which optional fields are populated depends on Type.
type TimelineParams ¶ added in v0.3.0
type TimelineParams struct {
// Limit is 1 to 200 (default 50). Anything else is a 400.
ListOptions
// Before is deprecated: it returns events strictly older than the
// timestamp and can skip events sharing an instant with the page
// boundary. It is ignored when Cursor is set. Prefer paging by cursor.
Before *time.Time `json:"-"`
}
TimelineParams paginates ContactService.ListTimeline.
type Timezone ¶
type Timezone struct {
// Name is the IANA identifier, for example "Europe/Berlin".
Name string `json:"name"`
// DisplayName is how to label it in a picker.
DisplayName string `json:"display_name"`
}
Timezone is one selectable IANA timezone.
type Token ¶
type Token struct {
// AccessToken is the bearer token used to authenticate requests.
AccessToken string `json:"access_token"`
// TokenType is the token type; the API returns "Bearer".
TokenType string `json:"token_type"`
// RefreshToken, when present, can be exchanged for a fresh access token.
RefreshToken string `json:"refresh_token,omitempty"`
// Scope is the space-delimited set of granted scopes.
Scope string `json:"scope,omitempty"`
// ExpiresIn is the lifetime in seconds as returned by the server. It is
// used to compute Expiry and is not otherwise meaningful afterwards.
ExpiresIn int64 `json:"expires_in,omitempty"`
// Expiry is the absolute time at which AccessToken expires. A zero value
// means the token never expires (or expiry is unknown).
Expiry time.Time `json:"-"`
}
Token is an OAuth 2.1 token as returned by the Warmbly token endpoint.
type TokenSource ¶
TokenSource yields valid tokens on demand, refreshing transparently. It is the same contract as golang.org/x/oauth2.TokenSource, so existing sources interoperate via a thin adapter.
func StaticTokenSource ¶
func StaticTokenSource(tok *Token) TokenSource
StaticTokenSource returns a TokenSource that always yields tok. It never refreshes and is mainly useful in tests or when a token is injected from the environment.
type TrackingDomainStatus ¶
type TrackingDomainStatus struct {
TrackingDomain string `json:"tracking_domain"`
TrackingDomainVerified bool `json:"tracking_domain_verified"`
TrackingDomainVerifiedAt *time.Time `json:"tracking_domain_verified_at"`
// CNAMETarget is the value to put in the CNAME record: this install's
// tracking host. Empty when the deployment has no tracking host.
CNAMETarget string `json:"cname_target"`
// Status is one of the TrackingStatus* constants.
Status string `json:"status"`
// Message explains Status in one sentence and is safe to show as-is.
Message string `json:"message"`
// Observed is what DNS actually returned, when it differs from the target.
Observed string `json:"observed,omitempty"`
// TrackingHostUnresolvable reports that the record is correct but this
// install's own tracking host has no DNS record, so nothing will be
// recorded. That is an operator fault, not a caller one.
TrackingHostUnresolvable bool `json:"tracking_host_unresolvable"`
}
TrackingDomainStatus is the state of a mailbox's custom click/open tracking domain. Verified turns true once the customer's subdomain CNAMEs to this install's tracking host. Until then opens and clicks go through the shared host, so an unverified domain never blocks sending.
Everything below TrackingDomainVerifiedAt is diagnostic, so a "pending" badge always comes with something to act on.
type TrialStatus ¶
type TrialStatus struct {
IsInTrial bool `json:"is_in_trial"`
TrialEndsAt *time.Time `json:"trial_ends_at,omitempty"`
DaysRemaining int `json:"days_remaining"`
IsExpired bool `json:"is_expired"`
IsSubscribed bool `json:"is_subscribed"`
}
TrialStatus is where the workspace stands in its free trial.
type TwoFAEnrollment ¶
type TwoFAEnrollment struct {
// Secret is the shared TOTP secret, and OTPAuthURI the same thing as a
// scannable otpauth:// URL.
Secret string `json:"secret"`
OTPAuthURI string `json:"otpauth_uri"`
}
TwoFAEnrollment is what a new authenticator needs to be set up.
type TwoFARecoveryCodes ¶
type TwoFARecoveryCodes struct {
RecoveryCodes []string `json:"recovery_codes"`
}
TwoFARecoveryCodes are the single-use codes that get an account back when the authenticator is lost. They are shown once.
type TwoFAStatus ¶
type TwoFAStatus struct {
Enabled bool `json:"enabled"`
}
TwoFAStatus reports whether the account has two-factor enabled.
type UniboxComposeParams ¶
type UniboxComposeParams struct {
// EmailAccountID picks the sending mailbox. Leave it empty (or set it to
// "auto") to let the server choose the best mailbox for the first
// recipient; see [UniboxService.ComposeCandidates].
EmailAccountID string `json:"email_account_id,omitempty"`
// FromTagID scopes an automatic pick to mailboxes carrying that tag. It is
// ignored when EmailAccountID names a mailbox.
FromTagID string `json:"from_tag_id,omitempty"`
To []string `json:"to"`
CC []string `json:"cc,omitempty"`
BCC []string `json:"bcc,omitempty"`
Subject string `json:"subject"`
BodyHTML string `json:"body_html,omitempty"`
BodyPlain string `json:"body_plain,omitempty"`
// SendMode is [SendModeInstant] (the default), [SendModeSmart] or
// [SendModeScheduled].
SendMode string `json:"send_mode,omitempty"`
ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
}
UniboxComposeParams sends a brand-new outbound email. Unlike a reply it is checked against the workspace suppression list before being queued: a suppressed recipient anywhere in To, CC or BCC fails the whole call with a 400.
type UniboxFolderCount ¶ added in v0.3.0
type UniboxFolderCount struct {
// Folder is one of the Folder* constants.
Folder string `json:"folder"`
Unread int `json:"unread"`
Total int `json:"total"`
}
UniboxFolderCount is one canonical folder's thread counts.
type UniboxLabelCount ¶
type UniboxLabelCount struct {
ID string `json:"id"`
Title string `json:"title"`
Color string `json:"color,omitempty"`
Unread int `json:"unread"`
Total int `json:"total"`
}
UniboxLabelCount is one tag's or label's share of the inbox.
type UniboxListParams ¶
type UniboxListParams struct {
ListOptions
// From and Subject are substring filters.
From string
Subject string
// Address matches conversations with one person in either direction: mail
// they sent, and mail sent to them.
Address string
// Direction is [DirectionSent] or [DirectionReceived]. Empty returns both.
Direction string
// Folder narrows to one canonical folder (a Folder* constant). Empty
// searches every folder except spam and trash; an unknown value is a 400.
Folder string
// Unseen restricts to threads with unread messages.
Unseen *bool
// AwaitingReply restricts to threads whose latest message you sent.
AwaitingReply *bool
// AgentDrafts restricts to threads with a pending inbox-agent draft.
AgentDrafts *bool
// Uncategorized restricts to threads carrying no conversation labels.
Uncategorized *bool
// Snoozed set to true returns only snoozed threads. Leave it nil to
// exclude snoozed threads, which is the default; the server ignores an
// explicit false. Set SnoozedAny to include snoozed and unsnoozed threads
// alike.
Snoozed *bool
SnoozedAny bool
// Since and Until bound the thread date.
Since time.Time
Until time.Time
// EmailID restricts to one mailbox; EmailIDs matches any of several.
EmailID string
EmailIDs []string
// CategoryIDs matches threads carrying any of the given conversation
// labels.
CategoryIDs []string
}
UniboxListParams filters and paginates the unified inbox.
type UniboxMailboxCount ¶
type UniboxMailboxCount struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name,omitempty"`
Unread int `json:"unread"`
Total int `json:"total"`
}
UniboxMailboxCount is one mailbox's share of the inbox.
type UniboxMessage ¶
type UniboxMessage struct {
ID string `json:"id"`
EmailID string `json:"email_id"`
// Mailbox is the provider-side folder id.
Mailbox int `json:"mailbox,omitempty"`
// Folder is the canonical folder the message is filed in: one of the
// Folder* constants. Empty on mail synced before folder tracking.
Folder string `json:"folder,omitempty"`
ThreadID string `json:"thread_id"`
MessageID string `json:"message_id,omitempty"`
GmailID string `json:"gmail_id,omitempty"`
ParentID string `json:"parent_id,omitempty"`
UID int `json:"uid,omitempty"`
ModSeq int `json:"mod_seq,omitempty"`
Flags []string `json:"flags,omitempty"`
BCC []string `json:"bcc,omitempty"`
CC []string `json:"cc,omitempty"`
FromAddr []string `json:"from_addr,omitempty"`
InReplyTo []string `json:"in_reply_to,omitempty"`
ReplyTo []string `json:"reply_to,omitempty"`
ToAddr []string `json:"to_addr,omitempty"`
Subject string `json:"subject"`
Size int `json:"size,omitempty"`
InternalDate time.Time `json:"internal_date"`
SentDate time.Time `json:"sent_date,omitempty"`
Snippet string `json:"snippet,omitempty"`
Seen bool `json:"seen"`
// BodyPlain is the plain-text body. BodyHTML is sanitized for display:
// scripts, event handlers and unsafe URL schemes are stripped before it
// leaves the API.
BodyPlain string `json:"body_plain,omitempty"`
BodyHTML string `json:"body_html,omitempty"`
// BodyTruncated is true when the stored body could not be read, in which
// case BodyPlain holds only the preview snippet. Show a notice rather than
// presenting the partial text as the whole message.
BodyTruncated bool `json:"body_truncated,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
}
UniboxMessage is a single message, as returned by UniboxService.Get and by the rows of UniboxService.Thread.
The two endpoints spell the envelope differently on the wire (the single read uses "from", "to" and "date"; thread rows use "from_addr", "to_addr" and "sent_date"). The SDK accepts both and exposes one shape. Bodies are only present on a single read; thread rows carry the snippet.
func (*UniboxMessage) UnmarshalJSON ¶ added in v0.3.0
func (m *UniboxMessage) UnmarshalJSON(data []byte) error
UnmarshalJSON accepts both envelope spellings the API uses for a message; see the type comment.
type UniboxOverview ¶
type UniboxOverview struct {
Total int `json:"total"`
Unread int `json:"unread"`
Today int `json:"today"`
Week int `json:"week"`
Snoozed int `json:"snoozed"`
AwaitingReply int `json:"awaiting_reply"`
// AwaitingAgentDraft counts threads with a pending inbox-agent draft
// waiting for review; see [UniboxService.AgentDrafts].
AwaitingAgentDraft int `json:"awaiting_agent_draft"`
// ScheduledPending is how many sends are queued but not yet out, capped
// for display at ScheduledPendingMax.
ScheduledPending int `json:"scheduled_pending"`
ScheduledPendingMax int `json:"scheduled_pending_max,omitempty"`
// Folders always lists all six canonical folders, zero-filled, in sidebar
// order.
Folders []UniboxFolderCount `json:"folders,omitempty"`
Mailboxes []UniboxMailboxCount `json:"mailboxes,omitempty"`
Tags []UniboxLabelCount `json:"tags,omitempty"`
Categories []UniboxLabelCount `json:"categories,omitempty"`
GeneratedAt time.Time `json:"generated_at,omitempty"`
WindowTodayStart time.Time `json:"window_today_start,omitempty"`
WindowWeekStart time.Time `json:"window_week_start,omitempty"`
}
UniboxOverview is the inbox sidebar: totals across the workspace, and per folder, per mailbox and per label.
type UniboxReplyParams ¶
type UniboxReplyParams struct {
EmailAccountID string `json:"email_account_id"`
To []string `json:"to"`
CC []string `json:"cc,omitempty"`
BCC []string `json:"bcc,omitempty"`
Subject string `json:"subject"`
BodyHTML string `json:"body_html,omitempty"`
BodyPlain string `json:"body_plain,omitempty"`
// InReplyTo holds the Message-IDs being replied to, and ThreadID keeps the
// message in the provider's conversation. When InReplyTo is empty and
// ThreadID is set, the server fills InReplyTo with the thread's latest
// Message-ID so the reply nests in the recipient's client too.
InReplyTo []string `json:"in_reply_to,omitempty"`
ThreadID string `json:"thread_id,omitempty"`
// SendMode is [SendModeInstant] (the default), [SendModeSmart] or
// [SendModeScheduled].
SendMode string `json:"send_mode,omitempty"`
ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
}
UniboxReplyParams sends a reply from a mailbox into an existing thread.
type UniboxService ¶
type UniboxService service
UniboxService is the unified inbox: every connected mailbox's mail in one place, plus replying, composing, snoozing, conversation labels, scheduled sends, autosaved drafts and the AI drafting surfaces.
List rows are previews: they carry a snippet, never the body. Read a single message with UniboxService.Get to receive its plain-text body and a sanitized HTML body.
func (*UniboxService) AgentDrafts ¶
func (s *UniboxService) AgentDrafts(ctx context.Context, opts ...RequestOption) ([]AgentDraft, *Response, error)
AgentDrafts returns the workspace's pending inbox-agent drafts, newest first. The agent only runs when the workspace has opted in via Organization.InboxAgentEnabled.
func (*UniboxService) ApproveAgentDraft ¶
func (s *UniboxService) ApproveAgentDraft(ctx context.Context, id, body string, opts ...RequestOption) (*SendResult, *Response, error)
ApproveAgentDraft sends an agent draft through the normal reply path, optionally replacing its body first. Approval is claimed before the send, so two concurrent approvals can never double-send; the loser gets a 409. If the send itself fails the draft returns to pending so it can be retried.
func (*UniboxService) CancelScheduled ¶
func (s *UniboxService) CancelScheduled(ctx context.Context, taskID string, opts ...RequestOption) (*Response, error)
CancelScheduled cancels a queued send. The cancellation is recorded immediately and the task short-circuits when its turn comes.
func (*UniboxService) Compose ¶
func (s *UniboxService) Compose(ctx context.Context, params *UniboxComposeParams, opts ...RequestOption) (*ComposeResult, *Response, error)
Compose sends a brand-new outbound email and reports which mailbox sent it.
func (*UniboxService) ComposeCandidates ¶
func (s *UniboxService) ComposeCandidates(ctx context.Context, to string, opts ...RequestOption) (*ComposeCandidates, *Response, error)
ComposeCandidates scores the workspace's mailboxes as senders for one recipient, so a picker can explain the automatic choice.
func (*UniboxService) DeleteDraft ¶
func (s *UniboxService) DeleteDraft(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DeleteDraft discards an autosaved compose draft.
func (*UniboxService) DiscardAgentDraft ¶
func (s *UniboxService) DiscardAgentDraft(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
DiscardAgentDraft throws an agent draft away unsent.
func (*UniboxService) DraftCompose ¶
func (s *UniboxService) DraftCompose(ctx context.Context, to, subject, instruction string, opts ...RequestOption) (*AIDraft, *Response, error)
DraftCompose writes a new email grounded in the contact record, prior correspondence and the workspace voice profile. It spends AI credits and never sends. When the request gives it too little to work with it returns a clarifying AIDraft.Question instead of a draft.
func (*UniboxService) DraftReply ¶
func (s *UniboxService) DraftReply(ctx context.Context, threadID, instruction string, opts ...RequestOption) (*AIDraft, *Response, error)
DraftReply writes a reply grounded in the thread's stored message text. It spends AI credits and never sends.
func (*UniboxService) Drafts ¶
func (s *UniboxService) Drafts(ctx context.Context, opts ...RequestOption) ([]ComposeDraft, *Response, error)
Drafts returns the caller's autosaved compose drafts.
func (*UniboxService) Get ¶
func (s *UniboxService) Get(ctx context.Context, id string, opts ...RequestOption) (*UniboxMessage, *Response, error)
Get returns a single message by id, including its plain-text body and a sanitized HTML body. Check UniboxMessage.BodyTruncated before treating BodyPlain as the whole message.
func (*UniboxService) List ¶
func (s *UniboxService) List(ctx context.Context, params *UniboxListParams, opts ...RequestOption) (*Page[UniboxThread], error)
List returns a page of inbox threads, newest first. Rows are previews; see UniboxService.Get for bodies.
func (*UniboxService) MarkFolderSeen ¶ added in v0.3.0
func (s *UniboxService) MarkFolderSeen(ctx context.Context, folder string, seen bool, opts ...RequestOption) (*Response, error)
MarkFolderSeen marks every message in one canonical folder (a Folder* constant) read or unread, workspace-wide. A folder sweep and an id list are different requests: the server rejects a body that carries both, which is why this is a separate method from UniboxService.MarkSeen.
func (*UniboxService) MarkSeen ¶
func (s *UniboxService) MarkSeen(ctx context.Context, emailIDs []string, seen bool, opts ...RequestOption) (*Response, error)
MarkSeen marks up to 500 messages read or unread by id. To sweep a whole folder use UniboxService.MarkFolderSeen.
func (*UniboxService) Overview ¶
func (s *UniboxService) Overview(ctx context.Context, opts ...RequestOption) (*UniboxOverview, *Response, error)
Overview returns the inbox sidebar counts.
func (*UniboxService) Reply ¶
func (s *UniboxService) Reply(ctx context.Context, params *UniboxReplyParams, opts ...RequestOption) (*SendResult, *Response, error)
Reply sends a reply into an existing thread.
func (*UniboxService) SaveDraft ¶
func (s *UniboxService) SaveDraft(ctx context.Context, id string, params *ComposeDraftParams, opts ...RequestOption) (*Response, error)
SaveDraft creates or replaces an autosaved compose draft. The id is client-generated, so repeating the call with the same id is an update rather than a new draft.
func (*UniboxService) Scheduled ¶
func (s *UniboxService) Scheduled(ctx context.Context, threadID string, opts ...RequestOption) ([]ScheduledSend, *Response, error)
Scheduled returns queued sends that have not left yet. Pass a threadID to narrow it to one conversation.
func (*UniboxService) SetThreadLabels ¶
func (s *UniboxService) SetThreadLabels(ctx context.Context, threadID string, categoryIDs []string, opts ...RequestOption) ([]MiniCategory, *Response, error)
SetThreadLabels replaces a thread's conversation labels wholesale, which makes it idempotent. Labels are contact categories; manage them with GroupService.
func (*UniboxService) Snooze ¶
func (s *UniboxService) Snooze(ctx context.Context, threadID string, until time.Time, opts ...RequestOption) (*UniboxSnooze, *Response, error)
Snooze hides a thread until the given time. Snoozing an already snoozed thread moves its wake-up time.
func (*UniboxService) Snoozes ¶
func (s *UniboxService) Snoozes(ctx context.Context, opts ...RequestOption) ([]UniboxSnooze, *Response, error)
Snoozes returns the caller's active snoozes.
func (*UniboxService) Thread ¶
func (s *UniboxService) Thread(ctx context.Context, threadID, emailID string, params *ListOptions, opts ...RequestOption) (*Page[UniboxMessage], error)
Thread returns a page of the messages in one conversation, oldest first. Pass an empty emailID to search every mailbox. Rows carry the snippet, not the body.
func (*UniboxService) ThreadLabels ¶
func (s *UniboxService) ThreadLabels(ctx context.Context, threadID string, opts ...RequestOption) ([]MiniCategory, *Response, error)
ThreadLabels returns the conversation labels on a thread.
func (*UniboxService) UnseenCount ¶
func (s *UniboxService) UnseenCount(ctx context.Context, emailID string, opts ...RequestOption) (int, *Response, error)
UnseenCount returns how many unread messages there are, across the workspace or in a single mailbox when emailID is set.
func (*UniboxService) Unsnooze ¶
func (s *UniboxService) Unsnooze(ctx context.Context, threadID string, opts ...RequestOption) (*Response, error)
Unsnooze returns a snoozed thread to the inbox immediately. It is idempotent: unsnoozing a thread that is not snoozed still succeeds.
type UniboxSnooze ¶
type UniboxSnooze struct {
ID string `json:"id"`
UserID string `json:"user_id"`
ThreadID string `json:"thread_id"`
SnoozedUntil time.Time `json:"snoozed_until"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
UniboxSnooze hides a thread until SnoozedUntil, at which point it returns to the inbox.
type UniboxThread ¶
type UniboxThread struct {
ID string `json:"id"`
EmailID string `json:"email_id"`
ThreadID string `json:"thread_id"`
FromAddr []string `json:"from_addr"`
ToAddr []string `json:"to_addr"`
Subject string `json:"subject"`
Snippet string `json:"snippet"`
// InternalDate is the provider's timestamp for the newest message.
InternalDate time.Time `json:"internal_date"`
Seen bool `json:"seen"`
MessageCount int `json:"message_count"`
HasUnread bool `json:"has_unread"`
// Labels are the conversation labels on the thread. They share the
// category registry with contact tags.
Labels []MiniCategory `json:"labels,omitempty"`
}
UniboxThread is one conversation in the unified inbox list. It is a preview row: Snippet is the only body text it carries.
type UnsubscribeSettings ¶ added in v0.3.0
type UnsubscribeSettings struct {
// Mode is [UnsubscribeModeText], [UnsubscribeModeLink] or
// [UnsubscribeModeOff].
Mode string `json:"mode"`
// Text is the sentence appended in text mode. Default: "If this isn't
// relevant, just reply and let me know and I won't email you again."
Text string `json:"text"`
// LinkIntro and LinkText make up the link-mode line, rendered as
// "<intro> <a>text</a>". Defaults: "Not the right person, or not
// interested?" and "Unsubscribe".
LinkIntro string `json:"link_intro"`
LinkText string `json:"link_text"`
}
UnsubscribeSettings is the organization default for the opt-out appended after the signature of every campaign email. Copy fields are single lines of at most 300 characters; whitespace is collapsed and longer text is cut. Blank copy falls back to the server defaults at send time.
type UpdateMemberParams ¶
type UpdateMemberParams struct {
RoleIDs []string `json:"role_ids,omitempty"`
RoleID *string `json:"role_id,omitempty"`
}
UpdateMemberParams replaces a member's assigned roles.
type UpsertContactConfig ¶ added in v0.3.0
type UpsertContactConfig struct {
Email string `json:"email"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Company string `json:"company,omitempty"`
Phone string `json:"phone,omitempty"`
// CustomFields are written into the contact's custom fields. A field
// whose value renders empty is left out rather than cleared.
CustomFields []TemplateField `json:"custom_fields,omitempty"`
// CategoryIDs tags the contact and SegmentIDs pins it into segments. Ids
// are validated on save.
CategoryIDs []string `json:"category_ids,omitempty"`
SegmentIDs []string `json:"segment_ids,omitempty"`
// CampaignID, when set, enrolls the contact in that campaign.
CampaignID string `json:"campaign_id,omitempty"`
// IfExists is [IfExistsUpdate] (the default) or [IfExistsSkip].
IfExists string `json:"if_exists,omitempty"`
}
UpsertContactConfig is the config of an ActionUpsertContact node. Every contact field is a Go template rendered against the event data. Email is required and is validated when the automation is saved; a rendered email that is empty or has no "@" fails the node at run time.
func (*UpsertContactConfig) Config ¶ added in v0.3.0
func (c *UpsertContactConfig) Config() (json.RawMessage, error)
Config renders the struct as an AutomationNode.Config value.
type UsageOverview ¶
type UsageOverview struct {
UserID string `json:"user_id"`
// Period is [UsagePeriodDay], [UsagePeriodWeek] or [UsagePeriodMonth].
Period string `json:"period"`
EmailAccounts EmailAccountUsage `json:"email_accounts"`
Campaigns CampaignUsage `json:"campaigns"`
Contacts ContactUsage `json:"contacts"`
API APIUsage `json:"api"`
}
UsageOverview is the organization's consumption against its plan.
type User ¶
type User struct {
ID string `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
AvatarURL *string `json:"avatar_url,omitempty"`
Roles []string `json:"roles,omitempty"`
ReferralSource *string `json:"referral_source,omitempty"`
OnboardingCompletedAt *time.Time `json:"onboarding_completed_at,omitempty"`
MaxOrganizations int `json:"max_organizations,omitempty"`
FreeTrialUsed bool `json:"free_trial_used,omitempty"`
// UndoSendSeconds is how long an instant send is held before it leaves, so
// the user can still cancel it.
UndoSendSeconds int `json:"undo_send_seconds,omitempty"`
// IsAdmin reports platform-admin access; AdminPermissions is the raw
// bitmask behind it. Both are only populated on the caller's own profile.
AdminPermissions uint64 `json:"admin_permissions,omitempty"`
IsAdmin bool `json:"is_admin,omitempty"`
// DeletionScheduledFor is set while the account is pending a hard delete.
DeletionScheduledAt *time.Time `json:"deletion_scheduled_at,omitempty"`
DeletionScheduledFor *time.Time `json:"deletion_scheduled_for,omitempty"`
// Folders, Tags and Categories are the user's label groups, returned on
// their own profile.
Folders []Group `json:"folders,omitempty"`
Tags []Group `json:"tags,omitempty"`
Categories []Group `json:"categories,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
User is a Warmbly user account.
func (*User) PendingDeletion ¶
PendingDeletion reports whether the account is scheduled for a hard delete.
type UserSession ¶
type UserSession struct {
ID string `json:"id"`
// Current marks the session making the request.
Current bool `json:"current"`
Browser string `json:"browser,omitempty"`
OS string `json:"os,omitempty"`
LocationCity string `json:"location_city,omitempty"`
LocationRegion string `json:"location_region,omitempty"`
LocationCountry string `json:"location_country,omitempty"`
CountryCode string `json:"country_code,omitempty"`
// AuthProvider is how the session was created, for example "password",
// "passkey", "apple" or "google".
AuthProvider string `json:"auth_provider"`
CreatedAt time.Time `json:"created_at"`
LastActiveAt time.Time `json:"last_active_at"`
}
UserSession is one active session on the account.
type VerifyResult ¶
type VerifyResult struct {
Email string `json:"email"`
// Status is [VerifyStatusValid], [VerifyStatusRisky],
// [VerifyStatusInvalid] or [VerifyStatusUnknown]. Unknown covers
// greylisting, timeouts and blocked outbound port 25; it is never a reason
// to drop an address.
Status string `json:"status"`
// SubStatus refines Status with one of the VerifySubStatus* constants, or
// "" when nothing more specific is known.
SubStatus string `json:"sub_status,omitempty"`
Reason string `json:"reason"`
IsCatchAll bool `json:"is_catch_all"`
HasMX bool `json:"has_mx"`
// Provider is who produced the verdict: "builtin" for the in-house probe,
// or the workspace's connected verification provider.
Provider string `json:"provider,omitempty"`
// Confidence is the scored certainty of Status, when the verifier
// provides one.
Confidence int `json:"confidence,omitempty"`
CheckedAt time.Time `json:"checked_at"`
}
VerifyResult is the outcome of verifying a single recipient address.
type WarmupAnalytics ¶
type WarmupAnalytics struct {
EmailAccountID string `json:"email_account_id"`
Email string `json:"email"`
DateRange DateRange `json:"date_range"`
Summary WarmupSummary `json:"summary"`
DailyStats []WarmupDailyStat `json:"daily_stats"`
}
WarmupAnalytics is warmup progress for one mailbox, or for the organization when no mailbox was named.
type WarmupAppealParams ¶
type WarmupAppealParams struct {
Reason string `json:"reason"`
}
WarmupAppealParams are the parameters for appealing a warmup ban.
type WarmupAppealResult ¶
type WarmupAppealResult struct {
AppealID string `json:"appeal_id"`
}
WarmupAppealResult identifies the appeal that was filed.
type WarmupBanStatus ¶
type WarmupBanStatus struct {
EmailAccountID string `json:"email_account_id"`
Blocked bool `json:"blocked"`
// HealthState is the mailbox's warmup health: "healthy", "watch",
// "throttled", "quarantined" or "blocked". Health is judged only on what
// happened while the mailbox was in the pool.
HealthState string `json:"health_state"`
// Reason, BlockedAt and BlockedUntil are omitted when the mailbox is not
// blocked.
Reason string `json:"reason,omitempty"`
BlockedAt *time.Time `json:"blocked_at,omitempty"`
BlockedUntil *time.Time `json:"blocked_until,omitempty"`
// CanAppeal reports whether [EmailService.AppealWarmupBan] is open to the
// owner; PendingAppeal reports that one has already been filed.
CanAppeal bool `json:"can_appeal"`
PendingAppeal bool `json:"pending_appeal"`
}
WarmupBanStatus describes whether a mailbox has been blocked from the warmup pool and whether that block can be appealed.
type WarmupDailyStat ¶
type WarmupDailyStat struct {
Date string `json:"date"`
EmailsSent int64 `json:"emails_sent"`
EmailsReplied int64 `json:"emails_replied"`
TargetVolume int64 `json:"target_volume"`
}
WarmupDailyStat is one day of warmup volume against its target.
type WarmupDomainPlacement ¶ added in v0.3.0
type WarmupDomainPlacement struct {
Provider string `json:"provider"`
Domain string `json:"domain"`
Delivered int64 `json:"delivered"`
Spam int64 `json:"spam"`
InboxRate float64 `json:"inbox_rate"`
SpamRate float64 `json:"spam_rate"`
}
WarmupDomainPlacement is one recipient domain's warmup placement rollup. Delivered counts verified warmup arrivals; Spam the ones flagged into junk.
type WarmupHealth ¶ added in v0.3.0
type WarmupHealth struct {
// State is one of the Band* constants.
State string `json:"state"`
// Score runs 0 to 100, higher being healthier.
Score float64 `json:"score"`
Reason string `json:"reason,omitempty"`
// SpamScore is the last content spam score, 0 to 100, lower being safer.
SpamScore int `json:"spam_score"`
BlockedUntil *time.Time `json:"blocked_until,omitempty"`
EvaluatedAt *time.Time `json:"evaluated_at,omitempty"`
}
WarmupHealth is a mailbox's standing in the warmup pool.
type WarmupRampHold ¶ added in v0.3.0
type WarmupRampHold struct {
// Placements is how many warmup messages landed in spam in the last 48
// hours, out of Sends.
Placements int `json:"placements"`
Sends int `json:"sends"`
VolumeCut bool `json:"volume_cut"`
// ResumesAt is when the ramp climbs again if nothing else lands in spam.
ResumesAt time.Time `json:"resumes_at"`
}
WarmupRampHold explains a frozen warmup ramp. It is present for the whole freeze; VolumeCut says whether today's volume is also reduced, which lasts a shorter window.
type WarmupRoutingRule ¶
type WarmupRoutingRule struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
// Priority orders evaluation; lower runs first.
Priority int `json:"priority"`
// SenderMatchType is one of the Match* constants; SenderMatchValue is
// ignored for [MatchAny].
SenderMatchType string `json:"sender_match_type"`
SenderMatchValue string `json:"sender_match_value,omitempty"`
// RecipientMatchType and RecipientMatchValue mirror the sender side.
RecipientMatchType string `json:"recipient_match_type"`
RecipientMatchValue string `json:"recipient_match_value,omitempty"`
// Weight scales how strongly a match is preferred.
Weight float64 `json:"weight"`
Enabled bool `json:"enabled"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
WarmupRoutingRule biases partner selection in the warmup pool.
type WarmupRoutingRuleParams ¶
type WarmupRoutingRuleParams struct {
Name string `json:"name"`
Priority int `json:"priority,omitempty"`
// SenderMatchType and RecipientMatchType are Match* constants.
SenderMatchType string `json:"sender_match_type"`
SenderMatchValue string `json:"sender_match_value,omitempty"`
RecipientMatchType string `json:"recipient_match_type"`
RecipientMatchValue string `json:"recipient_match_value,omitempty"`
Weight float64 `json:"weight,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
WarmupRoutingRuleParams creates or replaces a routing rule. The API replaces the rule wholesale on update, so send the complete desired state.
type WarmupRoutingService ¶
type WarmupRoutingService service
WarmupRoutingService manages warmup routing rules: preferences for how the premium partner pool pairs senders with recipients, for example "send to Gmail recipients only from Google-hosted mailboxes".
Rules are evaluated in Priority order and bias partner selection by Weight. They are preferences, not hard constraints: the pool falls back to an unmatched partner rather than sending nothing.
func (*WarmupRoutingService) Create ¶
func (s *WarmupRoutingService) Create(ctx context.Context, params *WarmupRoutingRuleParams, opts ...RequestOption) (*WarmupRoutingRule, *Response, error)
Create adds a routing rule.
func (*WarmupRoutingService) Delete ¶
func (s *WarmupRoutingService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete removes a routing rule.
func (*WarmupRoutingService) List ¶
func (s *WarmupRoutingService) List(ctx context.Context, opts ...RequestOption) ([]WarmupRoutingRule, *Response, error)
List returns the workspace's routing rules in priority order.
func (*WarmupRoutingService) Update ¶
func (s *WarmupRoutingService) Update(ctx context.Context, id string, params *WarmupRoutingRuleParams, opts ...RequestOption) (*WarmupRoutingRule, *Response, error)
Update replaces a routing rule.
type WarmupStatus ¶ added in v0.3.0
type WarmupStatus struct {
Enabled bool `json:"enabled"`
Paused bool `json:"paused"`
PausedAt *time.Time `json:"paused_at,omitempty"`
StartedAt time.Time `json:"started_at"`
// CurrentVolume is today's warmup sends so far; TargetVolume is today's
// target after any hold; MaxVolume is the configured ceiling.
CurrentVolume int `json:"current_volume"`
TargetVolume int `json:"target_volume"`
MaxVolume int `json:"max_volume"`
// ReplyRate is the configured warmup reply percentage.
ReplyRate int `json:"reply_rate"`
DaysActive int `json:"days_active"`
// RampHold explains a ramp that is not climbing, so a TargetVolume below
// the plain ramp is never an unexplained drop. Nil while the ramp is free
// to climb.
RampHold *WarmupRampHold `json:"ramp_hold,omitempty"`
}
WarmupStatus is a mailbox's warmup ramp as the scheduler will act on it.
type WarmupSummary ¶
type WarmupSummary struct {
TotalSent int64 `json:"total_sent"`
TotalReplied int64 `json:"total_replied"`
AverageDaily float64 `json:"average_daily"`
ReplyRate float64 `json:"reply_rate"`
// TargetProgress is how far the ramp has come, from 0 to 1.
TargetProgress float64 `json:"target_progress"`
DaysActive int `json:"days_active"`
}
WarmupSummary is the rollup for a warmup window.
type Webhook ¶
type Webhook struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
// URL is the HTTPS endpoint that receives deliveries.
URL string `json:"url"`
Description string `json:"description"`
// EventTypes are the event keys this endpoint subscribes to. An empty list
// means every non-firehose event.
EventTypes []string `json:"event_types"`
// Enabled reports whether deliveries are being attempted.
Enabled bool `json:"enabled"`
LastSuccessAt *time.Time `json:"last_success_at,omitempty"`
LastFailureAt *time.Time `json:"last_failure_at,omitempty"`
LastFailureReason *string `json:"last_failure_reason,omitempty"`
// ConsecutiveFailures drives the auto-disable circuit breaker.
ConsecutiveFailures int `json:"consecutive_failures"`
// OAuthApplicationID is set for app-scoped endpoints, whose URL host must
// stay inside the owning application's allowed webhook domains.
OAuthApplicationID *string `json:"oauth_application_id,omitempty"`
CreatedBy *string `json:"created_by,omitempty"`
// VerifiedAt is non-nil once the endpoint passed ownership verification.
// Only verified endpoints receive the real event stream.
VerifiedAt *time.Time `json:"verified_at,omitempty"`
// OwnershipConfirmed is true once the receiver echoed the challenge back,
// which proves control of the URL rather than mere reachability.
OwnershipConfirmed bool `json:"ownership_confirmed"`
// AutoDisabledAt is set when sustained failures tripped the breaker.
AutoDisabledAt *time.Time `json:"auto_disabled_at,omitempty"`
DisabledReason *string `json:"disabled_reason,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Webhook is a webhook endpoint as returned by the API.
type WebhookChallengePayload ¶ added in v0.3.0
type WebhookChallengePayload struct {
Challenge string `json:"challenge"`
// EndpointID identifies which of your endpoints is being verified, for a
// handler serving several.
EndpointID string `json:"endpoint_id"`
// Message is human-readable instructions, for someone reading the delivery
// in a log.
Message string `json:"message,omitempty"`
}
WebhookChallengePayload is the EventEndpointTest body, delivered only to the endpoint being verified. Echo WebhookChallengePayload.Challenge back — in your response body, or in the WebhookChallengeHeader — to confirm the endpoint and start receiving real events.
Take the token from here, after verifying the signature, rather than from the request header: the header is an unsigned convenience copy.
type WebhookCreateParams ¶
type WebhookCreateParams struct {
// URL is the HTTPS endpoint that will receive deliveries. Private and
// loopback addresses are rejected.
URL string `json:"url"`
Description string `json:"description,omitempty"`
// EventTypes are the keys to subscribe to. An empty list subscribes to
// every non-firehose event.
EventTypes []string `json:"event_types,omitempty"`
// Enabled defaults to true when nil.
Enabled *bool `json:"enabled,omitempty"`
}
WebhookCreateParams registers a webhook endpoint.
type WebhookDelivery ¶
type WebhookDelivery struct {
ID string `json:"id"`
EndpointID string `json:"endpoint_id"`
OrganizationID string `json:"organization_id"`
EventType string `json:"event_type"`
// EventID is stable across retries of the same event.
EventID string `json:"event_id"`
// Payload is the exact body POSTed to the endpoint.
Payload json.RawMessage `json:"payload"`
// Status is one of the Delivery* constants.
Status string `json:"status"`
AttemptCount int `json:"attempt_count"`
MaxAttempts int `json:"max_attempts"`
NextAttemptAt time.Time `json:"next_attempt_at"`
LastAttemptAt *time.Time `json:"last_attempt_at,omitempty"`
ResponseStatus *int `json:"response_status,omitempty"`
ResponseBodyExcerpt *string `json:"response_body_excerpt,omitempty"`
ErrorReason *string `json:"error_reason,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
WebhookDelivery is one delivery record, updated in place as attempts progress.
type WebhookDeliveryListParams ¶
type WebhookDeliveryListParams struct {
ListOptions
// EndpointID narrows to one endpoint. It is ignored by
// [WebhookService.EndpointDeliveries], which takes the id in the path.
EndpointID string
// Status is one of the Delivery* constants.
Status string
// EventType is one of the Event* constants.
EventType string
}
WebhookDeliveryListParams filters the delivery log.
type WebhookDrop ¶
type WebhookDrop struct {
EventType string `json:"event_type"`
Day time.Time `json:"day"`
DroppedWindows int `json:"dropped_windows"`
LastDroppedAt time.Time `json:"last_dropped_at"`
}
WebhookDrop is a daily rollup of events the dispatch throttle dropped, so rate limiting is visible rather than silent.
type WebhookEndpointList ¶
type WebhookEndpointList struct {
Endpoints []Webhook `json:"endpoints"`
EventTypes []WebhookEventDescriptor `json:"event_types"`
}
WebhookEndpointList is the response from WebhookService.List: the organization's endpoints plus the full event catalog, so a picker can be rendered without a second call.
type WebhookEvent ¶
type WebhookEvent struct {
// ID is the event id, stable across retries. Deduplicate on it.
ID string `json:"id"`
// EventType is the event key; compare it against the Event* constants.
EventType string `json:"event_type"`
OrganizationID string `json:"organization_id"`
CreatedAt time.Time `json:"created_at"`
// Data is the event-specific payload, left raw.
Data json.RawMessage `json:"data"`
}
WebhookEvent is the decoded body of a delivery, as produced by WebhookService.ConstructEvent. Switch on EventType, then unmarshal Data into the concrete payload for that event.
func ConstructWebhookEvent ¶
func ConstructWebhookEvent(payload []byte, signatureHeader, secret string, tolerance time.Duration) (*WebhookEvent, error)
ConstructWebhookEvent is WebhookService.ConstructEvent with an explicit timestamp tolerance. A tolerance of zero or less disables the replay check.
func (*WebhookEvent) Into ¶ added in v0.3.0
func (e *WebhookEvent) Into(v any) error
Into decodes the event's WebhookEvent.Data into v, which should be a pointer to the payload type for WebhookEvent.EventType. Most events carry the ids of what changed rather than the resource itself: refetch it over the REST API when you need its current state.
type WebhookEventDescriptor ¶
type WebhookEventDescriptor struct {
// Type is the event key, for example [EventCampaignReplyReceived].
Type string `json:"type"`
// Category groups the event for a picker; one of the WebhookCat* values.
Category string `json:"category"`
Description string `json:"description"`
// Firehose marks high-volume events. They are opt-in only: an endpoint
// with an empty event filter does not receive them.
Firehose bool `json:"firehose"`
}
WebhookEventDescriptor is one entry in the public event catalog.
type WebhookEventName ¶
type WebhookEventName = string
WebhookEventName is a stable webhook event key. The constants below are the full catalog at this SDK release; WebhookService.EventTypes is authoritative and stays current.
const ( // Mailbox lifecycle and health. EventEmailAccountConnected WebhookEventName = "email_account.connected" EventEmailAccountRemoved WebhookEventName = "email_account.removed" EventEmailAccountDisconnected WebhookEventName = "email_account.disconnected" EventEmailAccountError WebhookEventName = "email_account.error" // EventEmailAccountSynced is a firehose event: one per completed sync // pass, so subscribe to it explicitly or not at all. EventEmailAccountSynced WebhookEventName = "email_account.synced" EventEmailAccountHealthChanged WebhookEventName = "email_account.health_changed" // Campaign send pipeline. Everything up to and including the click is a // firehose event: one per message, excluded from the "all events" wildcard // and delivered only to an endpoint that lists it explicitly. EventCampaignEmailSent WebhookEventName = "campaign.email_sent" EventCampaignEmailDelivered WebhookEventName = "campaign.email_delivered" EventCampaignEmailOpened WebhookEventName = "campaign.email_opened" EventCampaignEmailClicked WebhookEventName = "campaign.email_clicked" EventCampaignEmailBounced WebhookEventName = "campaign.email_bounced" EventCampaignReplyReceived WebhookEventName = "campaign.reply_received" EventCampaignUnsubscribed WebhookEventName = "campaign.unsubscribed" // Campaign lifecycle and configuration. EventCampaignStarted WebhookEventName = "campaign.started" EventCampaignPaused WebhookEventName = "campaign.paused" EventCampaignCompleted WebhookEventName = "campaign.completed" EventCampaignCreated WebhookEventName = "campaign.created" EventCampaignUpdated WebhookEventName = "campaign.updated" EventCampaignDeleted WebhookEventName = "campaign.deleted" // EventCampaignDeliverabilityWarning fires when a campaign's rolling // bounce or complaint rate enters the early-warning band, short of an // auto-pause. EventCampaignDeliverabilityWarning WebhookEventName = "campaign.deliverability_warning" // EventCampaignAction fires from a notify action node in a sequence. EventCampaignAction WebhookEventName = "campaign.action" // Warmup. EventWarmupEmailSent is a firehose event: one per warmup // message, which is the highest-volume family the platform emits. EventWarmupEmailSent WebhookEventName = "warmup.email_sent" EventWarmupHealthChanged WebhookEventName = "warmup.health_changed" EventWarmupPlacementInSpam WebhookEventName = "warmup.placement_in_spam" EventWarmupQuarantined WebhookEventName = "warmup.quarantined" EventWarmupBlocked WebhookEventName = "warmup.blocked" // Deliverability. EventDeliverabilityBounce WebhookEventName = "deliverability.bounce" EventDeliverabilityComplaint WebhookEventName = "deliverability.complaint" // Meetings booked through a connected scheduling provider. EventMeetingBooked WebhookEventName = "meeting.booked" EventMeetingRescheduled WebhookEventName = "meeting.rescheduled" EventMeetingCanceled WebhookEventName = "meeting.canceled" // Inbox mail. These are firehose events: subscribe explicitly. EventInboxEmailReceived WebhookEventName = "inbox.email_received" EventInboxEmailUpdated WebhookEventName = "inbox.email_updated" EventInboxEmailDeleted WebhookEventName = "inbox.email_deleted" EventInboxReplyReceived WebhookEventName = "inbox.reply_received" // Contacts. // // EventContactCreated carries a payload of its own // ([ContactCreatedPayload]) rather than the generic audit shape the other // two use, and it is deliberately quiet: see the payload's documentation // for when it does not fire. EventContactCreated WebhookEventName = "contact.created" EventContactUpdated WebhookEventName = "contact.updated" EventContactDeleted WebhookEventName = "contact.deleted" // EventFormSubmitted fires when a hosted form receives a submission. It is // categorized under Contact, not a form category of its own, because lead // capture is what it is for. Payload: [FormSubmittedPayload]. EventFormSubmitted WebhookEventName = "form.submitted" // Bulk import and export. EventBulkOperationStarted WebhookEventName = "bulk_operation.started" EventBulkOperationCompleted WebhookEventName = "bulk_operation.completed" EventBulkOperationFailed WebhookEventName = "bulk_operation.failed" // Automations. EventAutomationCreated WebhookEventName = "automation.created" EventAutomationUpdated WebhookEventName = "automation.updated" EventAutomationDeleted WebhookEventName = "automation.deleted" EventAutomationRun WebhookEventName = "automation.run" // Templates. EventTemplateCreated WebhookEventName = "template.created" EventTemplateUpdated WebhookEventName = "template.updated" EventTemplateDeleted WebhookEventName = "template.deleted" // Team and access governance. EventTeamMemberInvited WebhookEventName = "team.member_invited" EventTeamMemberRemoved WebhookEventName = "team.member_removed" EventRoleCreated WebhookEventName = "role.created" EventRoleUpdated WebhookEventName = "role.updated" EventRoleDeleted WebhookEventName = "role.deleted" // CRM. EventCRMDealCreated WebhookEventName = "crm.deal_created" EventCRMDealUpdated WebhookEventName = "crm.deal_updated" EventCRMDealDeleted WebhookEventName = "crm.deal_deleted" EventCRMTaskCreated WebhookEventName = "crm.task_created" EventCRMTaskUpdated WebhookEventName = "crm.task_updated" EventCRMNoteCreated WebhookEventName = "crm.note_created" EventCRMPipelineUpdate WebhookEventName = "crm.pipeline_updated" // Workspace. EventLeadSyncSourceUpdated WebhookEventName = "lead_sync_source.updated" EventSettingsUpdated WebhookEventName = "settings.updated" EventSubscriptionUpdated WebhookEventName = "subscription.updated" // EventCustom is the developer-defined event published by a fire-event // sequence node. EventCustom WebhookEventName = "custom.event" // EventEndpointTest is the verification ping, delivered only to the // endpoint being verified. EventEndpointTest WebhookEventName = "webhook.test" )
Webhook event keys.
type WebhookService ¶
type WebhookService service
WebhookService manages webhook endpoints and their delivery log.
Each endpoint receives signed HTTP POSTs for the event types it subscribes to. Verify the WebhookSignatureHeader on every delivery with VerifyWebhookSignature — or, more conveniently, WebhookService.ConstructEvent — before trusting the payload.
A new endpoint does not receive the real event stream until it has proved ownership of its URL: call WebhookService.Verify, then echo the challenge value back from your handler.
func (*WebhookService) ConstructEvent ¶
func (s *WebhookService) ConstructEvent(payload []byte, signatureHeader, secret string) (*WebhookEvent, error)
ConstructEvent verifies a delivery's signature and decodes its payload.
Pass the raw, unmodified request body and the value of the WebhookSignatureHeader. It returns ErrInvalidWebhookSignature when the signature does not match, or ErrWebhookSignatureExpired when the timestamp falls outside DefaultWebhookTolerance.
func handler(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
event, err := client.Webhooks.ConstructEvent(body, r.Header.Get(warmbly.WebhookSignatureHeader), secret)
if err != nil {
http.Error(w, "bad signature", http.StatusBadRequest)
return
}
switch event.EventType {
case warmbly.EventCampaignReplyReceived:
// ...
}
}
Example ¶
Verify every webhook delivery before trusting its payload.
package main
import (
"fmt"
"log"
"github.com/warmbly/warmbly-go"
)
func main() {
client, _ := warmbly.New(warmbly.WithAPIKey("wmbly_..."))
var body []byte // the raw request body, unmodified
var signatureHeader string // r.Header.Get(warmbly.WebhookSignatureHeader)
const secret = "whsec_..."
event, err := client.Webhooks.ConstructEvent(body, signatureHeader, secret)
if err != nil {
// Either the signature did not match or it was too old to trust.
log.Fatal(err)
}
switch event.EventType {
case warmbly.EventCampaignReplyReceived:
fmt.Println("someone replied")
case warmbly.EventWarmupBlocked:
fmt.Println("a mailbox was blocked from the warmup pool")
}
}
Output:
func (*WebhookService) Create ¶
func (s *WebhookService) Create(ctx context.Context, params *WebhookCreateParams, opts ...RequestOption) (*WebhookWithSecret, *Response, error)
Create registers a new endpoint. The returned WebhookWithSecret carries the signing secret, which is only ever available here.
The endpoint receives no real events until it passes verification: call WebhookService.Verify and echo the challenge back.
func (*WebhookService) Delete ¶
func (s *WebhookService) Delete(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Delete permanently removes an endpoint.
func (*WebhookService) Deliveries ¶
func (s *WebhookService) Deliveries(ctx context.Context, params *WebhookDeliveryListParams, opts ...RequestOption) (*Page[WebhookDelivery], error)
Deliveries returns a page of the delivery log across every endpoint.
func (*WebhookService) Drops ¶
func (s *WebhookService) Drops(ctx context.Context, opts ...RequestOption) ([]WebhookDrop, *Response, error)
Drops returns the daily rollup of events the dispatch throttle dropped.
func (*WebhookService) EndpointDeliveries ¶
func (s *WebhookService) EndpointDeliveries(ctx context.Context, id string, params *WebhookDeliveryListParams, opts ...RequestOption) (*Page[WebhookDelivery], error)
EndpointDeliveries returns a page of one endpoint's delivery log.
func (*WebhookService) EventTypes ¶
func (s *WebhookService) EventTypes(ctx context.Context, opts ...RequestOption) ([]WebhookEventDescriptor, *Response, error)
EventTypes returns the full catalog of deliverable events.
func (*WebhookService) List ¶
func (s *WebhookService) List(ctx context.Context, opts ...RequestOption) (*WebhookEndpointList, *Response, error)
List returns the organization's webhook endpoints alongside the full event catalog. The list is not paginated.
func (*WebhookService) Redeliver ¶
func (s *WebhookService) Redeliver(ctx context.Context, deliveryID string, opts ...RequestOption) (*Response, error)
Redeliver re-queues a delivery for a fresh attempt cycle, keeping the same event id so a receiver deduplicating on it stays correct.
func (*WebhookService) RotateSecret ¶
func (s *WebhookService) RotateSecret(ctx context.Context, id string, opts ...RequestOption) (string, *Response, error)
RotateSecret issues a new signing secret and returns it. The previous secret stops verifying immediately, so deploy the new one before rotating.
func (*WebhookService) Update ¶
func (s *WebhookService) Update(ctx context.Context, id string, params *WebhookUpdateParams, opts ...RequestOption) (*Webhook, *Response, error)
Update replaces an endpoint's configuration.
func (*WebhookService) Verify ¶
func (s *WebhookService) Verify(ctx context.Context, id string, opts ...RequestOption) (*Response, error)
Verify sends an ownership challenge to the endpoint. The challenge arrives as a signed EventEndpointTest delivery carrying a WebhookChallengePayload; echo the token from its verified payload back — in the WebhookChallengeHeader of your response, or in the body — to confirm the endpoint and start receiving events.
It returns as soon as the challenge is queued, not once it lands: the endpoint's OwnershipConfirmed flag is what says it worked.
type WebhookUpdateParams ¶
type WebhookUpdateParams struct {
URL string `json:"url"`
Description string `json:"description,omitempty"`
EventTypes []string `json:"event_types,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
WebhookUpdateParams replaces an endpoint's configuration. Unlike most update params these are not merged: the API replaces URL, description, event types and enabled state wholesale, so send the complete desired state.
The secret is not changed here; use WebhookService.RotateSecret. Changing the URL host re-arms ownership verification.
type WebhookWithSecret ¶
WebhookWithSecret is a newly created endpoint together with its signing secret, which is returned only at creation. Store it securely; afterwards it can only be replaced with WebhookService.RotateSecret.
type WebsiteTrackingService ¶ added in v0.3.0
type WebsiteTrackingService service
WebsiteTrackingService configures website visitor tracking: the snippet a workspace installs on its own site so page views land on a contact's timeline. It governs consent mode, location precision, allowed hosts, retention and the site key.
These routes are session-only and need the manage-settings organization permission (OrgPermManageSettings): they are privacy governance, so they stay off the API-key surface. The snippet itself is not served by the API; it is loaded from the deployment's tracking host (WebsiteTrackingSettings.TrackingHost) as https://<tracking_host>/tracking.js with the site key in data-site, and page views go to that host too.
func (*WebsiteTrackingService) RotateKey ¶ added in v0.3.0
func (s *WebsiteTrackingService) RotateKey(ctx context.Context, opts ...RequestOption) (*WebsiteTrackingSettings, *Response, error)
RotateKey issues a new site key and returns the settings carrying it. The old key stops working at once, so every installed snippet has to be updated. It takes no body and is safe to repeat; each call issues another key.
func (*WebsiteTrackingService) Settings ¶ added in v0.3.0
func (s *WebsiteTrackingService) Settings(ctx context.Context, opts ...RequestOption) (*WebsiteTrackingSettings, *Response, error)
Settings returns the workspace's tracking configuration, creating a disabled one with a fresh site key on first call.
func (*WebsiteTrackingService) UpdateSettings ¶ added in v0.3.0
func (s *WebsiteTrackingService) UpdateSettings(ctx context.Context, params *WebsiteTrackingUpdateParams, opts ...RequestOption) (*WebsiteTrackingSettings, *Response, error)
UpdateSettings changes the tracking configuration and returns the result.
type WebsiteTrackingSettings ¶ added in v0.3.0
type WebsiteTrackingSettings struct {
OrganizationID string `json:"organization_id"`
// Enabled gates ingestion entirely.
Enabled bool `json:"enabled"`
// SiteKey identifies the workspace in the snippet. It is public — it only
// says which workspace a page view belongs to — but a leaked copy can be
// retired with [WebsiteTrackingService.RotateKey].
SiteKey string `json:"site_key"`
// ConsentMode is [WebsiteConsentExplicit] or [WebsiteConsentImplicit].
ConsentMode string `json:"consent_mode"`
// LocationPrecision is one of the WebsiteLocation* constants.
LocationPrecision string `json:"location_precision"`
// AllowedHosts are the hosts the site runs on; a host covers its
// subdomains. Page views from any other host are ignored, and campaign
// links only identify a visitor when they lead to one of these. Empty
// means views from anywhere are recorded but never tied to a contact.
AllowedHosts []string `json:"allowed_hosts"`
// RetentionDays is how long page views are kept, between
// [WebsiteRetentionMinDays] and [WebsiteRetentionMaxDays].
RetentionDays int `json:"retention_days"`
UpdatedAt time.Time `json:"updated_at"`
// TrackingHost is the deployment's tracking host, so a client can render
// the exact snippet. Empty when the install has none, in which case
// tracking cannot work.
TrackingHost string `json:"tracking_host"`
}
WebsiteTrackingSettings is a workspace's tracking configuration. It is created on first read with tracking disabled, so every workspace has a site key to show but nothing is accepted until Enabled is set.
type WebsiteTrackingUpdateParams ¶ added in v0.3.0
type WebsiteTrackingUpdateParams struct {
Enabled *bool `json:"enabled,omitempty"`
ConsentMode *string `json:"consent_mode,omitempty"`
LocationPrecision *string `json:"location_precision,omitempty"`
AllowedHosts *[]string `json:"allowed_hosts,omitempty"`
RetentionDays *int `json:"retention_days,omitempty"`
}
WebsiteTrackingUpdateParams changes the tracking configuration. Nil fields are left unchanged; an empty (non-nil) AllowedHosts clears the list.
type WriteParams ¶
type WriteParams struct {
Prompt string `json:"prompt"`
// Tone steers the register, for example "direct" or "friendly".
Tone string `json:"tone,omitempty"`
}
WriteParams asks for a fresh piece of copy.
Source Files
¶
- advisor.go
- agenttools.go
- ai.go
- analytics.go
- apikeys.go
- assistant.go
- auditlogs.go
- auth.go
- auth_service.go
- automations.go
- billing.go
- campaigns.go
- client.go
- cloudlink.go
- contacts.go
- crm.go
- doc.go
- emails.go
- errors.go
- forms.go
- groups.go
- integrations.go
- internal.go
- leadsync.go
- meta.go
- oauth.go
- oauth_flow.go
- options.go
- organization.go
- outreach.go
- pagination.go
- poollink.go
- segments.go
- suppressions.go
- teams.go
- templates.go
- unibox.go
- warmup.go
- webhooks.go
- websitetracking.go
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
analytics
command
Command analytics reads aggregate analytics: the workspace dashboard, deliverability health over the last 30 days, and per-mailbox status.
|
Command analytics reads aggregate analytics: the workspace dashboard, deliverability health over the last 30 days, and per-mailbox status. |
|
apikeys
command
Command apikeys demonstrates minting, listing and auditing API keys.
|
Command apikeys demonstrates minting, listing and auditing API keys. |
|
campaigns
command
Command campaigns demonstrates building and running a campaign: create it with its sequence, preflight it, send a test, start it, and list campaigns with automatic pagination.
|
Command campaigns demonstrates building and running a campaign: create it with its sequence, preflight it, send a test, start it, and list campaigns with automatic pagination. |
|
contacts
command
Command contacts demonstrates adding contacts, searching them with the faceted filter, reading the contact 360 view, and applying a bulk update.
|
Command contacts demonstrates adding contacts, searching them with the faceted filter, reading the contact 360 view, and applying a bulk update. |
|
emails
command
Command emails demonstrates managing connected mailboxes: listing them, driving warmup, checking whether a mailbox is blocked from the warmup pool, and sending a one-off message.
|
Command emails demonstrates managing connected mailboxes: listing them, driving warmup, checking whether a mailbox is blocked from the warmup pool, and sending a one-off message. |
|
errors
command
Command errors demonstrates error handling, retry configuration, and reading rate-limit state from a response.
|
Command errors demonstrates error handling, retry configuration, and reading rate-limit state from a response. |
|
gateway
command
Command gateway streams realtime events from a workspace and logs them until interrupted.
|
Command gateway streams realtime events from a workspace and logs them until interrupted. |
|
oauth
command
Command oauth demonstrates the OAuth 2.1 authorization-code flow with PKCE.
|
Command oauth demonstrates the OAuth 2.1 authorization-code flow with PKCE. |
|
oauthapps
command
Command oauthapps demonstrates registering and managing an OAuth 2.1 application, then using its credentials for machine-to-machine access through the client-credentials grant.
|
Command oauthapps demonstrates registering and managing an OAuth 2.1 application, then using its credentials for machine-to-machine access through the client-credentials grant. |
|
organization
command
Command organization demonstrates managing the workspace and its people: read its settings and limits, list members and roles, invite a teammate, then remove them.
|
Command organization demonstrates managing the workspace and its people: read its settings and limits, list members and roles, invite a teammate, then remove them. |
|
templates
command
Command templates demonstrates the lifecycle of a reply template: create, score the copy for spam risk, update, render, reorder and delete.
|
Command templates demonstrates the lifecycle of a reply template: create, score the copy for spam risk, update, render, reorder and delete. |
|
webhooks
command
Command webhooks demonstrates both sides of webhooks: registering an endpoint with the API, and running an HTTP receiver that verifies the signature on every delivery before acting on it.
|
Command webhooks demonstrates both sides of webhooks: registering an endpoint with the API, and running an HTTP receiver that verifies the signature on every delivery before acting on it. |
|
Package gateway is a client for the Warmbly realtime gateway: a persistent websocket that streams workspace events — campaign progress, engagement pulses, inbox arrivals, warmup health, automation runs — as they happen, instead of polling the REST API.
|
Package gateway is a client for the Warmbly realtime gateway: a persistent websocket that streams workspace events — campaign progress, engagement pulses, inbox arrivals, warmup health, automation runs — as they happen, instead of polling the REST API. |
|
internal
|
|
|
wsconn
Package wsconn is a minimal, dependency-free RFC 6455 WebSocket client.
|
Package wsconn is a minimal, dependency-free RFC 6455 WebSocket client. |