Documentation
¶
Overview ¶
Package custfind is the official Go client for the Custfind API: start lead searches, read scored leads, write and send emails, move deals and receive webhooks.
cf, err := custfind.NewClient() // reads CUSTFIND_API_KEY
created, err := cf.Searches.Create(ctx, custfind.CreateSearchParams{
Sector: "Dental clinic", Location: "Kadıköy, Istanbul", Limit: 25,
})
Every write is sent with an Idempotency-Key that stays the same across its retries, so a retried search never starts twice or reserves credits twice.
Example ¶
package main
import (
"context"
"fmt"
"log"
custfind "github.com/parevo/custfind-go"
)
func main() {
ctx := context.Background()
cf, err := custfind.NewClient() // reads CUSTFIND_API_KEY
if err != nil {
log.Fatal(err)
}
created, err := cf.Searches.Create(ctx, custfind.CreateSearchParams{
Sector: "Dental clinic",
Location: "Kadıköy, Istanbul",
Limit: 25, // caps the credits this search reserves
ExternalCustomerID: "acme-42", // optional: bill your own customer
})
if err != nil {
log.Fatal(err)
}
if _, err := cf.Searches.WaitForCompletion(ctx, created.JobID, custfind.WaitOptions{}); err != nil {
log.Fatal(err)
}
for lead, err := range cf.Searches.AllLeads(ctx, created.JobID, custfind.LeadListParams{}) {
if err != nil {
log.Fatal(err)
}
fmt.Println(lead.Name, lead.Email)
}
}
Output:
Index ¶
- Constants
- Variables
- func HasCode(err error, code string) bool
- func IsNotFound(err error) bool
- func IsPaymentRequired(err error) bool
- func Ptr[T any](v T) *T
- func VerifyWebhookSignature(payload []byte, header, secret string, tolerance time.Duration) error
- type Balance
- type Call
- type Client
- type CreateDealParams
- type CreateSearchParams
- type CreateSenderAccountParams
- type CreateWebhookParams
- type Customer
- type CustomersService
- func (s *CustomersService) Get(ctx context.Context, externalCustomerID string) (*Customer, error)
- func (s *CustomersService) List(ctx context.Context) ([]Customer, error)
- func (s *CustomersService) RemoveLimit(ctx context.Context, externalCustomerID string, opts ...RequestOption) error
- func (s *CustomersService) SetLimit(ctx context.Context, externalCustomerID string, monthlyCredits int, ...) (*Customer, error)
- type Deal
- type DealStageChangedData
- type DealsService
- type Error
- type Lead
- type LeadCRM
- type LeadCreatedData
- type LeadDetail
- type LeadEnrichment
- type LeadListParams
- type LeadsService
- func (s *LeadsService) AddNote(ctx context.Context, id, body string, opts ...RequestOption) (*Note, error)
- func (s *LeadsService) All(ctx context.Context, params LeadListParams) iter.Seq2[Lead, error]
- func (s *LeadsService) CRM(ctx context.Context, id string) (*LeadCRM, error)
- func (s *LeadsService) Get(ctx context.Context, id string) (*LeadDetail, error)
- func (s *LeadsService) List(ctx context.Context, params LeadListParams) (*Page[Lead], error)
- func (s *LeadsService) Outreach(ctx context.Context, id string) ([]OutreachMessage, error)
- func (s *LeadsService) WriteDraft(ctx context.Context, id string, regenerate bool, opts ...RequestOption) ([]OutreachMessage, error)
- type Me
- type Meeting
- type Note
- type Option
- type OutreachListParams
- type OutreachMessage
- type OutreachPage
- type OutreachRepliedData
- type OutreachSentData
- type OutreachService
- func (s *OutreachService) Get(ctx context.Context, id string) (*OutreachMessage, error)
- func (s *OutreachService) List(ctx context.Context, params OutreachListParams) (*OutreachPage, error)
- func (s *OutreachService) Rewrite(ctx context.Context, id string, params RewriteOutreachParams, ...) (*OutreachMessage, error)
- func (s *OutreachService) Send(ctx context.Context, id string, scheduledAt time.Time, opts ...RequestOption) (*OutreachMessage, error)
- func (s *OutreachService) Update(ctx context.Context, id string, params UpdateOutreachParams, ...) (*OutreachMessage, error)
- type OutreachStats
- type OutreachStatus
- type Page
- type Pipeline
- type PipelinesService
- type RequestOption
- type RewriteOutreachParams
- type Search
- type SearchCreated
- type SearchEventData
- type SearchStatus
- type SearchesService
- func (s *SearchesService) AllLeads(ctx context.Context, id string, params LeadListParams) iter.Seq2[Lead, error]
- func (s *SearchesService) Cancel(ctx context.Context, id string, opts ...RequestOption) (*Search, error)
- func (s *SearchesService) Create(ctx context.Context, params CreateSearchParams, opts ...RequestOption) (*SearchCreated, error)
- func (s *SearchesService) Get(ctx context.Context, id string) (*Search, error)
- func (s *SearchesService) Leads(ctx context.Context, id string, params LeadListParams) (*Page[Lead], error)
- func (s *SearchesService) List(ctx context.Context, limit int) ([]Search, error)
- func (s *SearchesService) WaitForCompletion(ctx context.Context, id string, opts WaitOptions) (*Search, error)
- type SenderAccount
- type SenderAccountsService
- func (s *SenderAccountsService) Create(ctx context.Context, params CreateSenderAccountParams, opts ...RequestOption) (*SenderAccount, error)
- func (s *SenderAccountsService) Delete(ctx context.Context, id string, opts ...RequestOption) error
- func (s *SenderAccountsService) List(ctx context.Context, externalCustomerID string) ([]SenderAccount, error)
- type Stage
- type Tag
- type Task
- type UpdateDealParams
- type UpdateOutreachParams
- type UpdateWebhookParams
- type Usage
- type UsageParams
- type UsageRow
- type WaitOptions
- type WebhookDelivery
- type WebhookEndpoint
- type WebhookEndpointCreated
- type WebhookEvent
- type WebhooksService
- func (s *WebhooksService) Create(ctx context.Context, params CreateWebhookParams, opts ...RequestOption) (*WebhookEndpointCreated, error)
- func (s *WebhooksService) Delete(ctx context.Context, id string, opts ...RequestOption) error
- func (s *WebhooksService) Deliveries(ctx context.Context, id string, limit int) ([]WebhookDelivery, error)
- func (s *WebhooksService) List(ctx context.Context) ([]WebhookEndpoint, error)
- func (s *WebhooksService) SendTest(ctx context.Context, id string, opts ...RequestOption) (*WebhookDelivery, error)
- func (s *WebhooksService) Update(ctx context.Context, id string, params UpdateWebhookParams, ...) (*WebhookEndpoint, error)
Examples ¶
Constants ¶
const ( CodeMissingAPIKey = "missing_api_key" CodeInvalidAPIKey = "invalid_api_key" CodeAPIRequiresPaidPlan = "api_requires_paid_plan" CodeInsufficientScope = "insufficient_scope" CodeCustomerLimitReached = "customer_limit_reached" CodeRateLimited = "rate_limited" CodeIdempotencyKeyReused = "idempotency_key_reused" CodeIdempotencyInProgress = "idempotency_in_progress" CodeInvalidIdempotencyKey = "invalid_idempotency_key" CodeResponseTooLargeReplay = "response_too_large_to_replay" )
Error codes the API returns in {"error": "<code>"}.
const ( ToneProfessional = "professional" ToneShort = "short" ToneCasual = "casual" )
Rewrite tones.
const ( EventSearchCompleted = "search.completed" EventSearchFailed = "search.failed" EventSearchCancelled = "search.cancelled" EventOutreachSent = "outreach.sent" EventOutreachReplied = "outreach.replied" EventDealStageChanged = "deal.stage_changed" EventLeadCreated = "lead.created" // EventWebhookTest is sent only by Webhooks.SendTest. EventWebhookTest = "webhook.test" )
Webhook event types.
const (
DefaultBaseURL = "https://api.custfind.com"
)
const DefaultWebhookTolerance = 5 * time.Minute
DefaultWebhookTolerance is how old a signed timestamp ConstructEvent accepts.
const SignatureHeader = "Custfind-Signature"
SignatureHeader is the header every webhook delivery is signed in: "t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<body>">".
const Version = "1.0.0"
Version is the SDK version, sent in the User-Agent.
Variables ¶
var ( ErrWebhookMalformedSignature = errors.New("custfind: malformed Custfind-Signature header") ErrWebhookTimestamp = errors.New("custfind: webhook timestamp outside tolerance") ErrWebhookSignatureMismatch = errors.New("custfind: webhook signature mismatch") )
Webhook verification errors.
Functions ¶
func IsNotFound ¶
IsNotFound reports whether err is a 404 from the API.
func IsPaymentRequired ¶
IsPaymentRequired reports whether err is a 402: no credits left, a customer's monthly cap reached, or a plan without API access.
Types ¶
type Balance ¶
type Balance struct {
Plan string `json:"plan"`
SubscriptionStatus string `json:"subscription_status"`
PeriodEnd *time.Time `json:"period_end,omitempty"`
Credits map[string]int `json:"credits"`
MonthlyCredits map[string]int `json:"monthly_credits"`
FairUseSoftReached bool `json:"fair_use_soft_reached"`
FairUseHardReached bool `json:"fair_use_hard_reached"`
}
Balance is the plan and what is left to spend. Credits are remaining meter balances ("lead", "ai_edit", "call_minute"); MonthlyCredits what the plan grants each month.
type Call ¶
type Call struct {
ID string `json:"id"`
LeadID string `json:"lead_id"`
Status string `json:"status"`
RecordingURL string `json:"recording_url,omitempty"`
Transcript string `json:"transcript,omitempty"`
Summary string `json:"summary,omitempty"`
DurationSeconds int `json:"duration_seconds"`
MinutesCharged int `json:"minutes_charged,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type Client ¶
type Client struct {
Searches *SearchesService
Leads *LeadsService
Outreach *OutreachService
Pipelines *PipelinesService
Deals *DealsService
Webhooks *WebhooksService
Customers *CustomersService
SenderAccounts *SenderAccountsService
// contains filtered or unexported fields
}
Client talks to the Custfind /v1 API. It is safe for concurrent use.
type CreateDealParams ¶
type CreateDealParams struct {
LeadID string `json:"lead_id"`
Title string `json:"title,omitempty"`
// StageID defaults to the first stage of the default pipeline.
StageID string `json:"stage_id,omitempty"`
ValueCents *int64 `json:"value_cents,omitempty"`
Currency string `json:"currency,omitempty"`
AssignedUserID string `json:"assigned_user_id,omitempty"`
}
type CreateSearchParams ¶
type CreateSearchParams struct {
Sector string `json:"sector"`
Location string `json:"location,omitempty"`
// Limit is the most leads to collect; 0 means the plan's maximum.
Limit int `json:"limit,omitempty"`
// SearchMode is "point" (default) or "country".
SearchMode string `json:"search_mode,omitempty"`
CountryCode string `json:"country_code,omitempty"`
Latitude *float64 `json:"latitude,omitempty"`
Longitude *float64 `json:"longitude,omitempty"`
RadiusKm *float64 `json:"radius_km,omitempty"`
Language string `json:"language,omitempty"`
// SellerProfileID picks the offer the leads are pitched with; empty
// uses the workspace default.
SellerProfileID string `json:"seller_profile_id,omitempty"`
// ExternalCustomerID is your own id for the customer this search is
// for; usage and monthly caps are tracked per customer.
ExternalCustomerID string `json:"external_customer_id,omitempty"`
}
CreateSearchParams starts a search. Set Limit to what you need: it caps the credits the search reserves.
type CreateSenderAccountParams ¶
type CreateSenderAccountParams struct {
Name string `json:"name"`
Email string `json:"email"`
SMTPHost string `json:"smtp_host"`
SMTPPort int `json:"smtp_port"`
SMTPUser string `json:"smtp_user"`
SMTPPass string `json:"smtp_pass"`
// ExternalCustomerID reserves the mailbox for one of your customers:
// that customer's leads are then emailed only from its own mailboxes.
ExternalCustomerID string `json:"external_customer_id,omitempty"`
}
CreateSenderAccountParams connects a mailbox. The password is write-only and tested against the server before the account is saved.
type CreateWebhookParams ¶
type Customer ¶
type Customer struct {
ExternalCustomerID string `json:"external_customer_id"`
MonthlyCreditLimit *int `json:"monthly_credit_limit"`
SpentThisMonth int `json:"spent_this_month"`
Remaining *int `json:"remaining"`
PeriodStart time.Time `json:"period_start"`
}
Customer is one of your customers (external_customer_id) and its monthly credit cap. MonthlyCreditLimit and Remaining are nil when uncapped.
type CustomersService ¶
type CustomersService struct {
// contains filtered or unexported fields
}
CustomersService manages monthly credit caps for your own customers (the external_customer_id you pass when starting searches).
func (*CustomersService) List ¶
func (s *CustomersService) List(ctx context.Context) ([]Customer, error)
func (*CustomersService) RemoveLimit ¶
func (s *CustomersService) RemoveLimit(ctx context.Context, externalCustomerID string, opts ...RequestOption) error
func (*CustomersService) SetLimit ¶
func (s *CustomersService) SetLimit(ctx context.Context, externalCustomerID string, monthlyCredits int, opts ...RequestOption) (*Customer, error)
SetLimit caps what the customer's searches may spend each month.
type Deal ¶
type Deal struct {
ID string `json:"id"`
LeadID string `json:"lead_id"`
PipelineID string `json:"pipeline_id"`
StageID string `json:"stage_id"`
Title string `json:"title"`
ValueCents *int64 `json:"value_cents,omitempty"`
Currency string `json:"currency"`
AssignedUserID *string `json:"assigned_user_id,omitempty"`
AssignedName string `json:"assigned_name,omitempty"`
ClosedAt *time.Time `json:"closed_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
LeadName string `json:"lead_name,omitempty"`
LeadEmail string `json:"lead_email,omitempty"`
LeadScore *int `json:"lead_score,omitempty"`
}
type DealStageChangedData ¶
type DealStageChangedData struct {
ID string `json:"id"`
LeadID string `json:"lead_id"`
PipelineID string `json:"pipeline_id"`
StageID string `json:"stage_id"`
StageName string `json:"stage_name"`
IsWon bool `json:"is_won"`
IsLost bool `json:"is_lost"`
PreviousStageID *string `json:"previous_stage_id"`
}
DealStageChangedData is the data of deal.stage_changed. PreviousStageID is nil when the deal was just created.
type DealsService ¶
type DealsService struct {
// contains filtered or unexported fields
}
func (*DealsService) Create ¶
func (s *DealsService) Create(ctx context.Context, params CreateDealParams, opts ...RequestOption) (*Deal, error)
func (*DealsService) Update ¶
func (s *DealsService) Update(ctx context.Context, id string, params UpdateDealParams, opts ...RequestOption) (*Deal, error)
Update changes the fields that are set, e.g. moves a deal to another stage.
type Error ¶
type Error struct {
// StatusCode is the HTTP status, or 0 when there was no response.
StatusCode int
// Code is the API's error value, e.g. "customer_limit_reached", or
// "http_<status>" when the body had none.
Code string
// Message holds extra detail when the API gave some.
Message string
// RetryAfter is the server's Retry-After, if it sent one.
RetryAfter time.Duration
// contains filtered or unexported fields
}
Error is an error response from the API, or a request that never got one (StatusCode 0, Code "network_error").
type Lead ¶
type Lead struct {
ID string `json:"id"`
ProjectID string `json:"project_id"`
Name string `json:"name"`
Phone string `json:"phone,omitempty"`
Website string `json:"website,omitempty"`
Email string `json:"email,omitempty"`
Address string `json:"address,omitempty"`
Category string `json:"category,omitempty"`
Rating *float64 `json:"rating,omitempty"`
Score *int `json:"score,omitempty"`
// ContactLocked is true when the plan's contact-reveal allowance hides
// this lead's email and phone.
ContactLocked bool `json:"contact_locked,omitempty"`
Source string `json:"source,omitempty"`
RegionCode string `json:"region_code,omitempty"`
RegionName string `json:"region_name,omitempty"`
Language string `json:"language,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UnsubscribedAt *time.Time `json:"unsubscribed_at,omitempty"`
SellerProfileID string `json:"seller_profile_id,omitempty"`
SellerProfileName string `json:"seller_profile_name,omitempty"`
DealID string `json:"deal_id,omitempty"`
DealStageID string `json:"deal_stage_id,omitempty"`
DealStageName string `json:"deal_stage_name,omitempty"`
AssignedUserID string `json:"assigned_user_id,omitempty"`
AssignedName string `json:"assigned_name,omitempty"`
}
type LeadCRM ¶
type LeadCRM struct {
Deal *Deal `json:"deal,omitempty"`
Notes []Note `json:"notes"`
Tasks []Task `json:"tasks"`
Tags []Tag `json:"tags"`
Outreach []OutreachMessage `json:"outreach"`
Meetings []Meeting `json:"meetings"`
}
LeadCRM is everything the CRM holds about a lead.
type LeadCreatedData ¶
type LeadCreatedData struct {
ID string `json:"id"`
SearchID *string `json:"search_id"`
ExternalCustomerID *string `json:"external_customer_id"`
Name string `json:"name"`
Phone *string `json:"phone"`
Website *string `json:"website"`
Address *string `json:"address"`
Category *string `json:"category"`
Rating *float64 `json:"rating"`
RegionName *string `json:"region_name"`
Language *string `json:"language"`
Source string `json:"source"`
}
LeadCreatedData is the data of lead.created.
type LeadDetail ¶
type LeadDetail struct {
Lead Lead `json:"lead"`
Enrichment *LeadEnrichment `json:"enrichment,omitempty"`
Outreach []OutreachMessage `json:"outreach,omitempty"`
Calls []Call `json:"calls,omitempty"`
}
LeadDetail is a lead with its enrichment, emails and calls.
type LeadEnrichment ¶
type LeadEnrichment struct {
ID string `json:"id"`
LeadID string `json:"lead_id"`
Email string `json:"email,omitempty"`
EmailStatus string `json:"email_status"`
EmailVerifiedAt *time.Time `json:"email_verified_at,omitempty"`
Socials []string `json:"socials"`
Metadata map[string]any `json:"metadata"`
CreatedAt time.Time `json:"created_at"`
}
type LeadListParams ¶
type LeadListParams struct {
Page int `url:"page"`
PageSize int `url:"page_size"` // at most 100
// Q searches name, email, phone and website.
Q string `url:"q"`
JobID string `url:"job_id"`
Category string `url:"category"`
// Contact is "email", "phone", "both", "website" or "none".
Contact string `url:"contact"`
MinScore *int `url:"min_score"`
MaxScore *int `url:"max_score"`
MinRating *float64 `url:"min_rating"`
MaxRating *float64 `url:"max_rating"`
Region string `url:"region"`
Language string `url:"language"`
// Source is "scrape", "manual", "import", "linkedin" or "manual_import".
Source string `url:"source"`
// OutreachStatus is "none", "pending", "sent", "opened" or "failed".
OutreachStatus string `url:"outreach_status"`
// Unsubscribed is "yes" or "no".
Unsubscribed string `url:"unsubscribed"`
StageID string `url:"stage_id"`
TagID string `url:"tag_id"`
// Sort is e.g. "score_desc", "rating_desc", "created_asc", "name".
// Empty means newest first.
Sort string `url:"sort"`
}
LeadListParams filters GET /v1/leads. Zero values are left out.
type LeadsService ¶
type LeadsService struct {
// contains filtered or unexported fields
}
LeadsService reads leads and acts on one.
func (*LeadsService) AddNote ¶
func (s *LeadsService) AddNote(ctx context.Context, id, body string, opts ...RequestOption) (*Note, error)
func (*LeadsService) All ¶
func (s *LeadsService) All(ctx context.Context, params LeadListParams) iter.Seq2[Lead, error]
All yields every lead matching params, page by page.
func (*LeadsService) Get ¶
func (s *LeadsService) Get(ctx context.Context, id string) (*LeadDetail, error)
Get returns a lead with its enrichment, emails and calls.
func (*LeadsService) List ¶
func (s *LeadsService) List(ctx context.Context, params LeadListParams) (*Page[Lead], error)
func (*LeadsService) Outreach ¶
func (s *LeadsService) Outreach(ctx context.Context, id string) ([]OutreachMessage, error)
Outreach returns the lead's emails.
func (*LeadsService) WriteDraft ¶
func (s *LeadsService) WriteDraft(ctx context.Context, id string, regenerate bool, opts ...RequestOption) ([]OutreachMessage, error)
WriteDraft writes the lead's email draft if it has none. With regenerate it rewrites the draft, which spends one AI edit.
type Me ¶
type Me struct {
OrganizationID string `json:"organization_id"`
APIKeyID string `json:"api_key_id"`
}
Me is the workspace and key behind the current API key.
type Meeting ¶
type Meeting struct {
ID string `json:"id"`
LeadID string `json:"lead_id"`
Title string `json:"title"`
Description string `json:"description"`
StartsAt time.Time `json:"starts_at"`
EndsAt time.Time `json:"ends_at"`
MeetLink string `json:"meet_link,omitempty"`
AttendeeEmail string `json:"attendee_email,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type Option ¶
type Option func(*Client)
Option configures a Client.
func WithAPIKey ¶
WithAPIKey sets the workspace key (cf_live_…). Defaults to CUSTFIND_API_KEY.
func WithBaseURL ¶
WithBaseURL points the client at another API host.
func WithHTTPClient ¶
WithHTTPClient sets the http.Client used for requests. Its Timeout is the per-attempt timeout.
func WithMaxRetries ¶
WithMaxRetries sets how often a request is retried after a network error, 429, 5xx or an idempotent write still in progress. Default 3.
func WithTimeout ¶
WithTimeout sets the per-attempt timeout. Default 30 s.
func WithUserAgent ¶
WithUserAgent prepends your own product to the User-Agent.
type OutreachListParams ¶
type OutreachListParams struct {
Page int `url:"page"`
PageSize int `url:"page_size"`
JobID string `url:"job_id"`
Status OutreachStatus `url:"status"`
Channel string `url:"channel"`
Q string `url:"q"`
// Sort is "created_at_asc", "sent_at_desc", "sent_at_asc",
// "lead_name_asc", "lead_name_desc" or "engagement_score_desc".
// Empty means newest first.
Sort string `url:"sort"`
}
type OutreachMessage ¶
type OutreachMessage struct {
ID string `json:"id"`
LeadID string `json:"lead_id"`
LeadName string `json:"lead_name,omitempty"`
LeadEmail string `json:"lead_email,omitempty"`
LeadEmailStatus string `json:"lead_email_status,omitempty"`
LeadEmailSuppressed bool `json:"lead_email_suppressed,omitempty"`
Channel string `json:"channel"`
EmailSubject string `json:"email_subject,omitempty"`
Message string `json:"message"`
ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
SentAt *time.Time `json:"sent_at,omitempty"`
SenderAccountID *string `json:"sender_account_id,omitempty"`
ErrorMessage *string `json:"error_message,omitempty"`
OpenedAt *time.Time `json:"opened_at,omitempty"`
OpenCount int `json:"open_count,omitempty"`
LastOpenedAt *time.Time `json:"last_opened_at,omitempty"`
ClickCount int `json:"click_count,omitempty"`
FirstClickedAt *time.Time `json:"first_clicked_at,omitempty"`
LastClickedAt *time.Time `json:"last_clicked_at,omitempty"`
EngagementScore int `json:"engagement_score,omitempty"`
StepPosition *int `json:"step_position,omitempty"`
SequenceStepName string `json:"sequence_step_name,omitempty"`
SequenceTotalSteps int `json:"sequence_total_steps,omitempty"`
// QualityIssues lists the automatic checks an AI draft failed; such a
// draft needs a human look before it is sent.
QualityIssues []string `json:"quality_issues,omitempty"`
PromptVersion string `json:"prompt_version,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type OutreachPage ¶
type OutreachPage struct {
Page[OutreachMessage]
Stats OutreachStats `json:"stats"`
}
type OutreachRepliedData ¶
type OutreachRepliedData struct {
ID string `json:"id"`
LeadID *string `json:"lead_id"`
OutreachMessageID *string `json:"outreach_message_id"`
ThreadID string `json:"thread_id"`
FromEmail string `json:"from_email"`
FromName *string `json:"from_name"`
Subject *string `json:"subject"`
Text *string `json:"text"` // the first 2000 characters
ReceivedAt time.Time `json:"received_at"`
}
OutreachRepliedData is the data of outreach.replied.
type OutreachSentData ¶
type OutreachSentData struct {
ID string `json:"id"`
LeadID string `json:"lead_id"`
Channel string `json:"channel"`
EmailSubject *string `json:"email_subject"`
SentAt time.Time `json:"sent_at"`
}
OutreachSentData is the data of outreach.sent.
type OutreachService ¶
type OutreachService struct {
// contains filtered or unexported fields
}
OutreachService edits and sends emails.
func (*OutreachService) Get ¶
func (s *OutreachService) Get(ctx context.Context, id string) (*OutreachMessage, error)
func (*OutreachService) List ¶
func (s *OutreachService) List(ctx context.Context, params OutreachListParams) (*OutreachPage, error)
func (*OutreachService) Rewrite ¶
func (s *OutreachService) Rewrite(ctx context.Context, id string, params RewriteOutreachParams, opts ...RequestOption) (*OutreachMessage, error)
Rewrite rewrites the email with AI by tone or instruction. It spends one AI edit, refunded if the rewrite fails.
func (*OutreachService) Send ¶
func (s *OutreachService) Send(ctx context.Context, id string, scheduledAt time.Time, opts ...RequestOption) (*OutreachMessage, error)
Send queues the email now, or for scheduledAt when it is not zero.
func (*OutreachService) Update ¶
func (s *OutreachService) Update(ctx context.Context, id string, params UpdateOutreachParams, opts ...RequestOption) (*OutreachMessage, error)
type OutreachStats ¶
type OutreachStats struct {
Total int `json:"total"`
Draft int `json:"draft"`
NeedsReview int `json:"needs_review"`
Scheduled int `json:"scheduled"`
Sent int `json:"sent"`
Failed int `json:"failed"`
Opened int `json:"opened"`
OpenRate int `json:"open_rate"`
AvgEngagement int `json:"avg_engagement"`
EngagementRate int `json:"engagement_rate"`
}
OutreachStats counts the emails matching an outreach list's filter.
type OutreachStatus ¶
type OutreachStatus string
OutreachStatus filters emails by state.
const ( OutreachDraft OutreachStatus = "draft" OutreachScheduled OutreachStatus = "scheduled" OutreachSent OutreachStatus = "sent" OutreachFailed OutreachStatus = "failed" )
type Page ¶
type Page[T any] struct { Items []T `json:"items"` Total int `json:"total"` Page int `json:"page"` PageSize int `json:"page_size"` }
Page is one page of a list.
type Pipeline ¶
type Pipeline struct {
ID string `json:"id"`
Name string `json:"name"`
IsDefault bool `json:"is_default"`
CreatedAt time.Time `json:"created_at"`
Stages []Stage `json:"stages"`
}
Pipeline is a deal pipeline with its stages in order.
type PipelinesService ¶
type PipelinesService struct {
// contains filtered or unexported fields
}
type RequestOption ¶
type RequestOption func(*requestConfig)
RequestOption changes a single call.
func WithIdempotencyKey ¶
func WithIdempotencyKey(key string) RequestOption
WithIdempotencyKey sends your own Idempotency-Key with a write instead of a generated one, which makes a retry across process restarts safe too. The API remembers a key for 24 hours.
type RewriteOutreachParams ¶
type RewriteOutreachParams struct {
Tone string `json:"tone,omitempty"`
Instruction string `json:"instruction,omitempty"`
}
RewriteOutreachParams needs a Tone, an Instruction or both.
type Search ¶
type Search struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
ProjectID string `json:"project_id"`
CreatedBy string `json:"created_by"`
Sector string `json:"sector"`
Location string `json:"location"`
Limit int `json:"limit"`
Latitude *float64 `json:"latitude,omitempty"`
Longitude *float64 `json:"longitude,omitempty"`
RadiusKm *float64 `json:"radius_km,omitempty"`
SearchMode string `json:"search_mode,omitempty"`
CountryCode string `json:"country_code,omitempty"`
Status SearchStatus `json:"status"`
Progress int `json:"progress"`
LeadsFound int `json:"leads_found"`
LeadsProcessed int `json:"leads_processed"`
CreditsReserved int `json:"credits_reserved,omitempty"`
CreditsConsumed int `json:"credits_consumed,omitempty"`
CreditsRefunded int `json:"credits_refunded,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
Source string `json:"source,omitempty"`
SellerProfileID string `json:"seller_profile_id,omitempty"`
APIKeyID string `json:"api_key_id,omitempty"`
ExternalCustomerID string `json:"external_customer_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type SearchCreated ¶
type SearchCreated struct {
ProjectID string `json:"project_id"`
JobID string `json:"job_id"`
Status SearchStatus `json:"status"`
}
type SearchEventData ¶
type SearchEventData struct {
ID string `json:"id"`
Status SearchStatus `json:"status"`
Sector string `json:"sector"`
Location string `json:"location"`
LeadsFound int `json:"leads_found"`
CreditsReserved int `json:"credits_reserved"`
CreditsConsumed int `json:"credits_consumed"`
Source string `json:"source"`
APIKeyID *string `json:"api_key_id"`
ExternalCustomerID *string `json:"external_customer_id"`
ErrorMessage *string `json:"error_message"`
}
SearchEventData is the data of search.completed, search.failed and search.cancelled.
type SearchStatus ¶
type SearchStatus string
SearchStatus is where a search is in its life.
const ( SearchQueued SearchStatus = "queued" SearchScraping SearchStatus = "scraping" SearchProcessing SearchStatus = "processing" SearchCompleted SearchStatus = "completed" SearchFailed SearchStatus = "failed" SearchCancelled SearchStatus = "cancelled" )
func (SearchStatus) Done ¶
func (s SearchStatus) Done() bool
Done reports whether the search has stopped (completed, failed or cancelled).
type SearchesService ¶
type SearchesService struct {
// contains filtered or unexported fields
}
SearchesService starts and follows lead searches.
func (*SearchesService) AllLeads ¶
func (s *SearchesService) AllLeads(ctx context.Context, id string, params LeadListParams) iter.Seq2[Lead, error]
AllLeads yields every lead of a search, page by page. Iterate a finished search: while one runs, new leads can shift the pages.
func (*SearchesService) Cancel ¶
func (s *SearchesService) Cancel(ctx context.Context, id string, opts ...RequestOption) (*Search, error)
Cancel stops a running search; unused credits are refunded.
func (*SearchesService) Create ¶
func (s *SearchesService) Create(ctx context.Context, params CreateSearchParams, opts ...RequestOption) (*SearchCreated, error)
Create starts a search. Set Limit to what you need: it caps the credits the search reserves.
func (*SearchesService) Leads ¶
func (s *SearchesService) Leads(ctx context.Context, id string, params LeadListParams) (*Page[Lead], error)
Leads returns one page of a search's leads. params.JobID is ignored.
func (*SearchesService) List ¶
List returns the latest searches, newest first; limit is at most 100 (0 means 20).
func (*SearchesService) WaitForCompletion ¶
func (s *SearchesService) WaitForCompletion(ctx context.Context, id string, opts WaitOptions) (*Search, error)
WaitForCompletion polls until the search completes, fails or is cancelled, and returns it. Bound the wait with ctx.
type SenderAccount ¶
type SenderAccount struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
SMTPHost string `json:"smtp_host"`
SMTPPort int `json:"smtp_port"`
SMTPUser string `json:"smtp_user"`
DailyLimit int `json:"daily_limit"`
ExternalCustomerID string `json:"external_customer_id,omitempty"`
IMAPSyncStatus string `json:"imap_sync_status,omitempty"`
IMAPSyncedAt *time.Time `json:"imap_synced_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type SenderAccountsService ¶
type SenderAccountsService struct {
// contains filtered or unexported fields
}
SenderAccountsService manages the mailboxes emails go out from.
func (*SenderAccountsService) Create ¶
func (s *SenderAccountsService) Create(ctx context.Context, params CreateSenderAccountParams, opts ...RequestOption) (*SenderAccount, error)
Create connects a mailbox; the SMTP login is tested before it is saved.
func (*SenderAccountsService) Delete ¶
func (s *SenderAccountsService) Delete(ctx context.Context, id string, opts ...RequestOption) error
func (*SenderAccountsService) List ¶
func (s *SenderAccountsService) List(ctx context.Context, externalCustomerID string) ([]SenderAccount, error)
List returns the mailboxes; a non-empty externalCustomerID returns only that customer's.
type Task ¶
type Task struct {
ID string `json:"id"`
LeadID string `json:"lead_id"`
DealID *string `json:"deal_id,omitempty"`
AssignedName string `json:"assigned_name,omitempty"`
Title string `json:"title"`
DueAt *time.Time `json:"due_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type UpdateDealParams ¶
type UpdateDealParams struct {
Title *string `json:"title,omitempty"`
PipelineID *string `json:"pipeline_id,omitempty"`
StageID *string `json:"stage_id,omitempty"`
ValueCents *int64 `json:"value_cents,omitempty"`
Currency *string `json:"currency,omitempty"`
AssignedUserID *string `json:"assigned_user_id,omitempty"`
}
UpdateDealParams changes only the fields that are set.
type UpdateOutreachParams ¶
type UpdateWebhookParams ¶
type UpdateWebhookParams struct {
URL *string `json:"url,omitempty"`
Description *string `json:"description,omitempty"`
Events []string `json:"events,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
UpdateWebhookParams changes only the fields that are set.
type UsageParams ¶
type WaitOptions ¶
WaitOptions tune WaitForCompletion.
type WebhookDelivery ¶
type WebhookDelivery struct {
ID string `json:"id"`
EventID string `json:"event_id"`
EventType string `json:"event_type"`
Status string `json:"status"` // pending, delivered or failed
Attempts int `json:"attempts"`
LastStatusCode *int `json:"last_status_code,omitempty"`
LastError string `json:"last_error,omitempty"`
NextAttemptAt *time.Time `json:"next_attempt_at,omitempty"`
DeliveredAt *time.Time `json:"delivered_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type WebhookEndpoint ¶
type WebhookEndpointCreated ¶
type WebhookEndpointCreated struct {
Endpoint WebhookEndpoint `json:"endpoint"`
Secret string `json:"secret"`
}
WebhookEndpointCreated carries the signing secret, shown only once.
type WebhookEvent ¶
type WebhookEvent struct {
ID string `json:"id"`
Type string `json:"type"`
CreatedAt time.Time `json:"created_at"`
OrganizationID string `json:"organization_id"`
Data json.RawMessage `json:"data"`
}
WebhookEvent is the body of a webhook delivery. Decode Data with Event.Decode into the struct for its Type (SearchEventData, …).
func ConstructEvent ¶
func ConstructEvent(payload []byte, header, secret string) (*WebhookEvent, error)
ConstructEvent verifies a webhook delivery and returns its event. Pass the raw body exactly as received, before any JSON parsing:
payload, _ := io.ReadAll(r.Body)
event, err := custfind.ConstructEvent(payload, r.Header.Get(custfind.SignatureHeader), secret)
if err != nil { w.WriteHeader(400); return }
if event.Type == custfind.EventSearchCompleted {
var d custfind.SearchEventData
_ = event.Decode(&d)
}
Deliveries can repeat; use event.ID to handle each event once.
func (*WebhookEvent) Decode ¶
func (e *WebhookEvent) Decode(v any) error
Decode unmarshals the event's data into v.
type WebhooksService ¶
type WebhooksService struct {
// contains filtered or unexported fields
}
func (*WebhooksService) Create ¶
func (s *WebhooksService) Create(ctx context.Context, params CreateWebhookParams, opts ...RequestOption) (*WebhookEndpointCreated, error)
Create registers an endpoint. The returned Secret is shown only now; keep it to verify deliveries with ConstructEvent.
func (*WebhooksService) Delete ¶
func (s *WebhooksService) Delete(ctx context.Context, id string, opts ...RequestOption) error
func (*WebhooksService) Deliveries ¶
func (s *WebhooksService) Deliveries(ctx context.Context, id string, limit int) ([]WebhookDelivery, error)
Deliveries returns the endpoint's latest deliveries (limit 0 = default).
func (*WebhooksService) List ¶
func (s *WebhooksService) List(ctx context.Context) ([]WebhookEndpoint, error)
func (*WebhooksService) SendTest ¶
func (s *WebhooksService) SendTest(ctx context.Context, id string, opts ...RequestOption) (*WebhookDelivery, error)
SendTest queues a webhook.test delivery to the endpoint.
func (*WebhooksService) Update ¶
func (s *WebhooksService) Update(ctx context.Context, id string, params UpdateWebhookParams, opts ...RequestOption) (*WebhookEndpoint, error)