instantly

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Oct 17, 2026 License: MIT Imports: 10 Imported by: 0

README

📬  go-instantly

Unofficial Golang Library for the Instantly.ai API (V2).


Release Go Version License


CI / CD    Build Last Commit      Quality    Coverage
Security    Scorecard Security      Community    Contributors Bitcoin


Project Navigation
🚀 Installation 🧪 Examples & Tests 📚 Documentation
🤝 Contributing 🛠️ Code Standards ⚡ Benchmarks
🤖 AI Usage ⚖️ License 👥 Maintainers

📦 Installation

go-instantly requires a supported release of Go.

go get github.com/mrz1836/go-instantly

💡 Usage

This library targets the Instantly.ai API V2 only. V2 is not backwards compatible with V1 and uses its own credentials — a V1 key will not authenticate against V2, so create a V2 API key in your workspace settings and pass it to NewClient. Every request is then authenticated with an Authorization: Bearer <key> header against https://api.instantly.ai.

The SDK is organized AWS-SDK-v2 style: a tiny root package holds the shared Client, and each API resource lives in its own subpackage (email, campaign, account, …). Construct the client once and hand it to a resource service. Importing a resource pulls in only that resource plus the root package and the standard library — never testify or the other resources.

package main

import (
	"context"
	"log"

	"github.com/mrz1836/go-instantly"
	"github.com/mrz1836/go-instantly/email"
)

func main() {
	client := instantly.NewClient("[API-KEY]")
	emails := email.New(client)

	err := emails.SendTest(context.Background(), email.SendTestRequest{
		EAccount:           "sender@example.com",
		ToAddressEmailList: "recipient@example.com",
		Subject:            "Testing the sending account",
		Body: email.Body{
			HTML: "<p>Hello from go-instantly.</p>",
			Text: "Hello from go-instantly.",
		},
	})
	if err != nil {
		log.Fatal(err)
	}
}

List endpoints take functional options, so only the filters you actually pass are sent:

page, err := emails.List(ctx,
	email.WithLimit(50),
	email.WithIsUnread(true),
	email.WithMode(email.ModeFocused),
)

Pagination is cursor based. List returns a single page, and ListIter walks every page for you as a range-over-func iterator:

for message, err := range emails.ListIter(ctx, email.WithIsUnread(true)) {
	if err != nil {
		return err
	}
	log.Printf("%s: %s", message.ID, message.Subject)
}

Some endpoints report a failure inside an otherwise successful HTTP 200 response. This library turns those into real errors, so err != nil catches every failure regardless of which shape it arrived in:

var apiErr *instantly.APIError
if errors.As(err, &apiErr) && apiErr.Code == instantly.ErrCodeAccountAuthError {
	// the sending account failed to authenticate
}

📚 Documentation

View the generated documentation, or the Instantly.ai API reference for endpoint details, scopes, and per-endpoint rate limits.

Heads up! go-instantly is intentionally light on dependencies. The only external package it uses is the excellent testify suite—and that's just for our tests. You can drop this library into your projects without dragging along extra baggage.


Supported API Coverage

Coverage is built one resource at a time against the Instantly V2 OpenAPI spec — 171 operations across 127 endpoints in 28 resource groups. Each resource is its own Go package (AWS-SDK-v2 style). 171 / 171 operations · 28 / 28 resources ship today (Email, Account, Account-Campaign Mappings, Campaign, Lead, Lead List, Lead Label, Campaign Subsequence, Email Verification, Inbox Placement Test, Inbox Placement Analytics, Inbox Placement Report, SuperSearch Enrichment, Webhook, Webhook Event, Workspace, Workspace Member, Workspace Group Member, Workspace Billing, Block List Entry, Custom Tag, Custom Tag Mapping, API Key, Audit Log, Background Job, CRM Actions, OAuth, DFY Email Account Order) — the SDK now covers the entire Instantly.ai V2 API.

  • Email API — (email/)
  • Account API — (account/)
    • POST /api/v2/accounts - Create account (account.Service.Create)
    • GET /api/v2/accounts - List accounts (account.Service.List / ListIter)
    • GET /api/v2/accounts/{email} - Get account (account.Service.Get)
    • PATCH /api/v2/accounts/{email} - Patch account (account.Service.Update)
    • DELETE /api/v2/accounts/{email} - Delete account (account.Service.Delete)
    • POST /api/v2/accounts/{email}/pause - Pause an account (account.Service.Pause)
    • POST /api/v2/accounts/pause - Pause multiple accounts (account.Service.PauseBulk)
    • POST /api/v2/accounts/{email}/resume - Resume an account (account.Service.Resume)
    • POST /api/v2/accounts/{email}/mark-fixed - Mark an account fixed (account.Service.MarkFixed)
    • POST /api/v2/accounts/move - Move accounts between workspaces (account.Service.Move)
    • POST /api/v2/accounts/warmup/enable - Enable warmup (account.Service.EnableWarmup)
    • POST /api/v2/accounts/warmup/disable - Disable warmup (account.Service.DisableWarmup)
    • POST /api/v2/accounts/warmup-analytics - Warmup analytics (account.Service.WarmupAnalytics)
    • GET /api/v2/accounts/analytics/daily - Daily analytics (account.Service.DailyAnalytics)
    • GET /api/v2/accounts/ctd/status - Custom tracking domain status (account.Service.CtdStatus)
    • POST /api/v2/accounts/test/vitals - Test account vitals (account.Service.TestVitals)
  • Account-Campaign Mappings — (accountcampaign/)
    • GET /api/v2/account-campaign-mappings/{email} - Campaigns for an account (accountcampaign.Service.List / ListIter)
  • Campaign API — (campaign/)
    • POST /api/v2/campaigns - Create campaign (campaign.Service.Create)
    • GET /api/v2/campaigns - List campaigns (campaign.Service.List / ListIter)
    • GET /api/v2/campaigns/{id} - Get campaign (campaign.Service.Get)
    • PATCH /api/v2/campaigns/{id} - Patch campaign (campaign.Service.Update)
    • DELETE /api/v2/campaigns/{id} - Delete campaign (campaign.Service.Delete)
    • POST /api/v2/campaigns/{id}/activate - Activate/resume (campaign.Service.Activate)
    • POST /api/v2/campaigns/{id}/pause - Pause (campaign.Service.Pause)
    • POST /api/v2/campaigns/{id}/duplicate - Duplicate (campaign.Service.Duplicate)
    • POST /api/v2/campaigns/{id}/share - Share (campaign.Service.Share)
    • POST /api/v2/campaigns/{id}/export - Export to JSON (campaign.Service.Export)
    • POST /api/v2/campaigns/{id}/from-export - Create from export (campaign.Service.CreateFromExport)
    • POST /api/v2/campaigns/{id}/variables - Add variables (campaign.Service.AddVariables)
    • GET /api/v2/campaigns/{id}/sending-status - Sending status (campaign.Service.SendingStatus)
    • GET /api/v2/campaigns/count-launched - Launched count (campaign.Service.CountLaunched)
    • GET /api/v2/campaigns/search-by-contact - Search by contact (campaign.Service.SearchByContact)
    • GET /api/v2/campaigns/analytics - Analytics (campaign.Service.Analytics)
    • GET /api/v2/campaigns/analytics/overview - Analytics overview (campaign.Service.AnalyticsOverview)
    • GET /api/v2/campaigns/analytics/daily - Daily analytics (campaign.Service.DailyAnalytics)
    • GET /api/v2/campaigns/analytics/steps - Steps analytics (campaign.Service.StepsAnalytics)
  • Lead API — (lead/)
    • POST /api/v2/leads - Create lead (lead.Service.Create)
    • POST /api/v2/leads/list - List leads, POST-body filters + cursor (lead.Service.List / ListIter)
    • GET /api/v2/leads/{id} - Get lead (lead.Service.Get)
    • PATCH /api/v2/leads/{id} - Patch lead (lead.Service.Update)
    • DELETE /api/v2/leads/{id} - Delete lead (lead.Service.Delete)
    • DELETE /api/v2/leads - Bulk delete, body on DELETE (lead.Service.BulkDelete)
    • POST /api/v2/leads/add - Bulk add (lead.Service.BulkAdd)
    • POST /api/v2/leads/bulk-assign - Bulk assign (lead.Service.BulkAssign)
    • POST /api/v2/leads/move - Move leads (lead.Service.Move)
    • POST /api/v2/leads/merge - Merge leads (lead.Service.Merge)
    • POST /api/v2/leads/update-interest-status - Update interest (lead.Service.UpdateInterestStatus)
    • POST /api/v2/leads/subsequence/remove - Remove from subsequence (lead.Service.RemoveFromSubsequence)
    • POST /api/v2/leads/subsequence/move - Move to subsequence (lead.Service.MoveToSubsequence)
  • Lead List API — (leadlist/)
    • POST /api/v2/lead-lists - Create (leadlist.Service.Create)
    • GET /api/v2/lead-lists - List (leadlist.Service.List / ListIter)
    • GET /api/v2/lead-lists/{id} - Get (leadlist.Service.Get)
    • PATCH /api/v2/lead-lists/{id} - Patch (leadlist.Service.Update)
    • DELETE /api/v2/lead-lists/{id} - Delete (leadlist.Service.Delete)
    • GET /api/v2/lead-lists/{id}/verification-stats - Verification stats (leadlist.Service.VerificationStats)
  • Lead Label API — (leadlabel/)
    • POST /api/v2/lead-labels - Create (leadlabel.Service.Create)
    • GET /api/v2/lead-labels - List (leadlabel.Service.List / ListIter)
    • GET /api/v2/lead-labels/{id} - Get (leadlabel.Service.Get)
    • PATCH /api/v2/lead-labels/{id} - Patch (leadlabel.Service.Update)
    • DELETE /api/v2/lead-labels/{id} - Delete (leadlabel.Service.Delete)
    • POST /api/v2/lead-labels/ai-reply-label - Test AI reply label (leadlabel.Service.TestAIReplyLabel)
  • Campaign Subsequence API — (subsequence/)
    • POST /api/v2/subsequences - Create (subsequence.Service.Create)
    • GET /api/v2/subsequences - List (subsequence.Service.List / ListIter)
    • GET /api/v2/subsequences/{id} - Get (subsequence.Service.Get)
    • PATCH /api/v2/subsequences/{id} - Patch (subsequence.Service.Update)
    • DELETE /api/v2/subsequences/{id} - Delete (subsequence.Service.Delete)
    • POST /api/v2/subsequences/{id}/duplicate - Duplicate (subsequence.Service.Duplicate)
    • POST /api/v2/subsequences/{id}/pause - Pause (subsequence.Service.Pause)
    • POST /api/v2/subsequences/{id}/resume - Resume (subsequence.Service.Resume)
    • GET /api/v2/subsequences/{id}/sending-status - Sending status (subsequence.Service.SendingStatus)
  • Email Verification API — (emailverification/)
    • POST /api/v2/email-verification - Create verification (emailverification.Service.Create)
    • GET /api/v2/email-verification/{email} - Check verification (emailverification.Service.Check)
  • Inbox Placement Test API — (inboxtest/)
    • POST /api/v2/inbox-placement-tests - Create test (inboxtest.Service.Create)
    • GET /api/v2/inbox-placement-tests - List tests (inboxtest.Service.List / ListIter)
    • GET /api/v2/inbox-placement-tests/{id} - Get test (inboxtest.Service.Get)
    • PATCH /api/v2/inbox-placement-tests/{id} - Patch test (inboxtest.Service.Update)
    • DELETE /api/v2/inbox-placement-tests/{id} - Delete test (inboxtest.Service.Delete)
    • GET /api/v2/inbox-placement-tests/email-service-provider-options - ESP options (inboxtest.Service.ESPOptions)
  • Inbox Placement Analytics API — (inboxanalytics/)
    • GET /api/v2/inbox-placement-analytics - List analytics (inboxanalytics.Service.List / ListIter)
    • GET /api/v2/inbox-placement-analytics/{id} - Get analytics (inboxanalytics.Service.Get)
    • POST /api/v2/inbox-placement-analytics/stats-by-test-id - Stats by test id (inboxanalytics.Service.StatsByTestID)
    • POST /api/v2/inbox-placement-analytics/deliverability-insights - Deliverability insights (inboxanalytics.Service.DeliverabilityInsights)
    • POST /api/v2/inbox-placement-analytics/stats-by-date - Stats by date (inboxanalytics.Service.StatsByDate)
  • Inbox Placement Report API — (inboxreport/)
    • GET /api/v2/inbox-placement-reports - List reports (inboxreport.Service.List / ListIter)
    • GET /api/v2/inbox-placement-reports/{id} - Get report (inboxreport.Service.Get)
  • SuperSearch Enrichment API — (supersearch/)
    • POST /api/v2/supersearch-enrichment/ - Create enrichment (supersearch.Service.Create)
    • GET /api/v2/supersearch-enrichment/{resource_id} - Get enrichment for resource (supersearch.Service.Get)
    • PATCH /api/v2/supersearch-enrichment/{resource_id}/settings - Update settings (supersearch.Service.UpdateSettings)
    • POST /api/v2/supersearch-enrichment/run - Run enrichment (supersearch.Service.Run)
    • POST /api/v2/supersearch-enrichment/ai - Create AI enrichment (supersearch.Service.CreateAI)
    • GET /api/v2/supersearch-enrichment/ai/{resource_id}/in-progress - In-progress AI jobs (supersearch.Service.AIInProgress)
    • POST /api/v2/supersearch-enrichment/count-leads-from-supersearch - Count leads (supersearch.Service.CountLeads)
    • POST /api/v2/supersearch-enrichment/preview-leads-from-supersearch - Preview leads (supersearch.Service.PreviewLeads)
    • POST /api/v2/supersearch-enrichment/enrich-leads-from-supersearch - Enrich leads (supersearch.Service.EnrichLeads)
    • POST /api/v2/supersearch-enrichment/signal-keywords-facet - Facet signal keywords (supersearch.Service.SignalKeywords)
    • GET /api/v2/supersearch-enrichment/history/{resource_id} - Enrichment history (supersearch.Service.History)
  • Webhook API — (webhook/)
    • POST /api/v2/webhooks - Create webhook (webhook.Service.Create)
    • GET /api/v2/webhooks - List webhooks (webhook.Service.List / ListIter)
    • GET /api/v2/webhooks/{id} - Get webhook (webhook.Service.Get)
    • PATCH /api/v2/webhooks/{id} - Patch webhook (webhook.Service.Update)
    • DELETE /api/v2/webhooks/{id} - Delete webhook (webhook.Service.Delete)
    • GET /api/v2/webhooks/event-types - List event types (webhook.Service.EventTypes)
    • POST /api/v2/webhooks/{id}/test - Send a test delivery (webhook.Service.Test)
    • POST /api/v2/webhooks/{id}/resume - Resume a disabled webhook (webhook.Service.Resume)
  • Webhook Event API — (webhookevent/)
    • GET /api/v2/webhook-events - List events (webhookevent.Service.List / ListIter)
    • GET /api/v2/webhook-events/{id} - Get event (webhookevent.Service.Get)
    • GET /api/v2/webhook-events/summary - Overview summary (webhookevent.Service.Summary)
    • GET /api/v2/webhook-events/summary-by-date - Summary by date (webhookevent.Service.SummaryByDate)
  • Workspace API — (workspace/)
    • GET /api/v2/workspaces/current - Get current workspace (workspace.Service.Get)
    • PATCH /api/v2/workspaces/current - Patch workspace (workspace.Service.Update)
    • POST /api/v2/workspaces/current/schedule-for-removal - Schedule removal (workspace.Service.ScheduleRemoval)
    • DELETE /api/v2/workspaces/current/schedule-for-removal - Cancel removal (workspace.Service.CancelRemoval)
    • POST /api/v2/workspaces/current/whitelabel-domain - Set agency domain (workspace.Service.SetAgencyDomain)
    • GET /api/v2/workspaces/current/whitelabel-domain - Get domain info (workspace.Service.DomainInfo)
    • DELETE /api/v2/workspaces/current/whitelabel-domain - Delete agency domain (workspace.Service.DeleteAgencyDomain)
    • POST /api/v2/workspaces/current/change-owner - Change owner (workspace.Service.ChangeOwner)
  • Workspace Member API — (workspacemember/)
    • POST /api/v2/workspace-members - Invite member (workspacemember.Service.Create)
    • GET /api/v2/workspace-members - List members (workspacemember.Service.List / ListIter)
    • GET /api/v2/workspace-members/{id} - Get member (workspacemember.Service.Get)
    • PATCH /api/v2/workspace-members/{id} - Patch member (workspacemember.Service.Update)
    • DELETE /api/v2/workspace-members/{id} - Remove member (workspacemember.Service.Delete)
  • Workspace Group Member API — (workspacegroup/)
    • POST /api/v2/workspace-group-members - Invite sub workspace (workspacegroup.Service.Create)
    • GET /api/v2/workspace-group-members - List group members (workspacegroup.Service.List / ListIter)
    • GET /api/v2/workspace-group-members/{id} - Get group member (workspacegroup.Service.Get)
    • DELETE /api/v2/workspace-group-members/{id} - Remove group member (workspacegroup.Service.Delete)
    • GET /api/v2/workspace-group-members/admin - Get admin workspace (workspacegroup.Service.Admin)
  • Workspace Billing API — (workspacebilling/)
    • GET /api/v2/workspace-billing/plan-details - Plan details (workspacebilling.Service.PlanDetails)
    • GET /api/v2/workspace-billing/subscription-details - Subscription details (workspacebilling.Service.SubscriptionDetails)
  • Block List Entry API — (blocklist/)
    • POST /api/v2/block-lists-entries - Create entry (blocklist.Service.Create)
    • GET /api/v2/block-lists-entries - List entries (blocklist.Service.List / ListIter)
    • DELETE /api/v2/block-lists-entries - Delete all entries (blocklist.Service.DeleteAll)
    • GET /api/v2/block-lists-entries/{id} - Get entry (blocklist.Service.Get)
    • PATCH /api/v2/block-lists-entries/{id} - Patch entry (blocklist.Service.Update)
    • DELETE /api/v2/block-lists-entries/{id} - Delete entry (blocklist.Service.Delete)
    • POST /api/v2/block-lists-entries/bulk-create - Bulk create (blocklist.Service.BulkCreate)
    • POST /api/v2/block-lists-entries/bulk-delete - Bulk delete (blocklist.Service.BulkDelete)
    • GET /api/v2/block-lists-entries/download - Download CSV, raw bytes (blocklist.Service.Download)
  • Custom Tag API — (customtag/)
    • POST /api/v2/custom-tags - Create tag (customtag.Service.Create)
    • GET /api/v2/custom-tags - List tags (customtag.Service.List / ListIter)
    • GET /api/v2/custom-tags/{id} - Get tag (customtag.Service.Get)
    • PATCH /api/v2/custom-tags/{id} - Patch tag (customtag.Service.Update)
    • DELETE /api/v2/custom-tags/{id} - Delete tag (customtag.Service.Delete)
    • POST /api/v2/custom-tags/toggle-resource - Assign/unassign tags (customtag.Service.Toggle)
  • Custom Tag Mapping API — (customtagmapping/)
    • GET /api/v2/custom-tag-mappings - List mappings (customtagmapping.Service.List / ListIter)
  • API Key API — (apikey/)
    • POST /api/v2/api-keys - Create API key (apikey.Service.Create)
    • GET /api/v2/api-keys - List API keys (apikey.Service.List / ListIter)
    • DELETE /api/v2/api-keys/{id} - Delete API key (apikey.Service.Delete)
  • Audit Log API — (auditlog/)
    • GET /api/v2/audit-logs - List audit logs (auditlog.Service.List / ListIter)
  • Background Job API — (backgroundjob/)
    • GET /api/v2/background-jobs - List background jobs (backgroundjob.Service.List / ListIter)
    • GET /api/v2/background-jobs/{id} - Get a background job (backgroundjob.Service.Get)
  • CRM Actions API — (crm/)
    • GET /api/v2/crm-actions/phone-numbers - List phone numbers (crm.Service.ListPhoneNumbers)
    • DELETE /api/v2/crm-actions/phone-numbers/{id} - Delete a phone number (crm.Service.DeletePhoneNumber)
  • OAuth API — (oauth/)
    • POST /api/v2/oauth/google/init - Start a Google OAuth session (oauth.Service.InitGoogle)
    • POST /api/v2/oauth/microsoft/init - Start a Microsoft OAuth session (oauth.Service.InitMicrosoft)
    • GET /api/v2/oauth/session/status/{sessionId} - Poll session status (oauth.Service.SessionStatus)
  • DFY Email Account Order API — (dfy/)
    • POST /api/v2/dfy-email-account-orders - Place (or simulate) an order (dfy.Service.Create)
    • GET /api/v2/dfy-email-account-orders - List orders (dfy.Service.List / ListIter)
    • GET /api/v2/dfy-email-account-orders/accounts - List ordered accounts (dfy.Service.ListAccounts / ListAccountsIter)
    • POST /api/v2/dfy-email-account-orders/accounts/cancel - Cancel accounts (dfy.Service.CancelAccounts)
    • POST /api/v2/dfy-email-account-orders/domains/similar - Generate similar domains (dfy.Service.GenerateSimilarDomains)
    • POST /api/v2/dfy-email-account-orders/domains/check - Check domain availability (dfy.Service.CheckDomains)
    • POST /api/v2/dfy-email-account-orders/domains/pre-warmed-up-list - List pre-warmed-up domains (dfy.Service.PreWarmedUpDomains)

Every V2 resource now ships — there is no remaining planned coverage.

Notes on the counts. The Analytics area (7 operations) is cross-cutting — 3 endpoints live under Account and 4 under Campaign, so they are counted within those resources rather than as a separate group. Three additional tags — CustomPromptTemplate, EmailTemplate, and SalesFlow — are declared in the V2 API but currently expose no public endpoints.

Adding a resource? Follow the durable recipe in docs/adding-a-resource.md — the email package is the reference implementation.

Client Configuration (Functional Options)

The client is immutable after construction: configure it once with functional options. This is safer than mutating shared state and is the idiomatic Go pattern. Available options:

Option Purpose
WithHTTPClient(*http.Client) Custom transport, proxy, or timeout
WithBaseURL(string) Point at a test server or gateway
WithUserAgent(string) Set the User-Agent header
WithHTTPHeader(key, value) Add an extra header to every request
package main

import (
    "net/http"
    "time"

    "github.com/mrz1836/go-instantly"
)

// ....

client := instantly.NewClient("[API-KEY]",
    instantly.WithHTTPClient(&http.Client{Timeout: 30 * time.Second}),
    instantly.WithUserAgent("my-app/1.0"),
)

// ...

Need an endpoint the typed resource packages do not wrap yet? The low-level plumbing is exported as an escape hatch: client.Get, client.Post, client.Patch, client.Put, client.Delete, client.Do, and client.DoRaw (raw bytes, for CSV and other non-JSON responses).

Development Setup (Getting Started)

Install MAGE-X build tool for development:

# Install MAGE-X for development and building
go install github.com/mrz1836/mage-x/cmd/magex@latest
magex update:install
Library Deployment

This project uses goreleaser for streamlined binary and library deployment to GitHub. To get started, install it via:

brew install goreleaser

The release process is defined in the .goreleaser.yml configuration file.

Then create and push a new Git tag using:

magex version:bump bump=patch push=true branch=master

This process ensures consistent, repeatable releases with properly versioned artifacts and citation metadata.

Build Commands

View all build commands

magex help
GitHub Workflows

All workflows are driven by modular configuration in .github/env/ — no YAML editing required.

View all workflows and the control center →

Updating Dependencies

To update all dependencies (Go modules, linters, and related tools), run:

magex deps:update

This command ensures all dependencies are brought up to date in a single step, including Go modules and any managed tools. It is the recommended way to keep your development environment and CI in sync with the latest versions.


🧪 Examples & Tests

All unit tests and fuzz tests run via GitHub Actions and use Go version 1.25.x. View the configuration file.

Run all tests (fast):

magex test

Run all tests with race detector (slower):

magex test:race

Browse the runnable usage samples in examples/examples.go.

Note: the test suite runs entirely against an in-repo mock router. No test contacts the live Instantly.ai API, and the examples file is illustrative — it is compiled, never executed by CI.


⚡ Benchmarks

Run the Go benchmarks:

magex bench
📊 Performance Results

A benchmark suite now covers the hot paths — query encoding and path building (Query.Encode, BuildPath), the response-error probe (checkResponse), cursor iteration (Iterate), the reusable list helpers (JoinPath, ApplyOptions), and a representative resource decode and round-trip (CampaignDecode, CampaignGet). Run magex bench to measure them on your own hardware; numbers vary by machine, so they are reproduced locally rather than pinned here.


🛠️ Code Standards

Read more about this Go project's code standards.


🤖 AI Usage & Assistant Guidelines

Read the AI Usage & Assistant Guidelines for details on how AI is used in this project and how to interact with the AI assistants.


👥 Maintainers

MrZ
MrZ

🤝 Contributing

View the contributing guidelines and please follow the code of conduct.

How can I help?

All kinds of contributions are welcome 🙌! The most basic way to show your support is to star 🌟 the project, or to raise issues 💬. You can also support this project by becoming a sponsor on GitHub 👏 or by making a bitcoin donation to ensure this journey continues indefinitely! 🚀

Stars


📝 License

License

Documentation

Overview

Package instantly is the foundation of the Instantly.ai V2 API SDK.

It provides the Client — an authenticated, immutable connection to the API — along with the low-level request plumbing (Do, Get, Post, Patch, Put, Delete, DoRaw), the shared query builder (Query), the generic pagination helper (Iterate), typed API errors (APIError), and cross-resource enums.

Typed access to each API resource lives in its own subpackage — for example github.com/mrz1836/go-instantly/email — so importing one resource pulls in only that resource plus this foundation and the standard library, never the test-support code or the other resources.

Construct a client once and hand it to a resource service:

client := instantly.NewClient("[API-KEY]")
svc := email.New(client)
page, err := svc.List(ctx, email.WithLimit(50))

Index

Examples

Constants

View Source
const (
	// ErrCodeAccountAuthError indicates the sending account failed to authenticate.
	ErrCodeAccountAuthError = "ACC_AUTH_ERROR"

	// ErrCodeAccountNotFound indicates the requested sending account does not exist.
	ErrCodeAccountNotFound = "ACC_NOT_FOUND"

	// ErrCodeAccountUnknownError indicates an unclassified sending account failure.
	ErrCodeAccountUnknownError = "ACC_UNKNOWN_ERROR"
)

Error codes the API delivers inside an HTTP 200 response body.

Variables

This section is empty.

Functions

func BuildPath

func BuildPath(base string, values url.Values) string

BuildPath appends encoded query parameters to a path, returning the bare path when there are none.

func DeleteResult added in v0.2.0

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

DeleteResult performs a DELETE and decodes the response into a fresh T. It returns a nil *T on any error.

func GetResult added in v0.2.0

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

GetResult performs a GET and decodes the response into a fresh T.

It collapses the out := &T{}; if err := client.Get(...); return out, nil block every read method used to repeat. On any error it returns a nil *T, so a failed decode never hands back a partly populated value.

func Iterate

func Iterate[T any](ctx context.Context, fetch FetchPage[T]) iter.Seq2[*T, error]

Iterate turns a paginated fetch into a range-over-func sequence, following the cursor until the API stops returning one.

It centralizes every termination guard so each resource's ListIter is a thin closure over its own List call:

  • the context is checked before every page, so a cancellation between pages stops iteration instead of issuing another request;
  • the first error is yielded once with a nil *T and ends iteration;
  • an empty page ends iteration even if the API keeps returning a cursor, which bounds the total number of requests;
  • iteration stops once the next cursor comes back empty.

Iteration also stops as soon as the consumer breaks out of the range loop, so no page is fetched that the consumer never reads.

func JoinPath added in v0.2.0

func JoinPath(base string, segments ...string) string

JoinPath escapes each segment and joins it onto base with a slash.

It replaces the hand-built base + "/" + url.PathEscape(id) joins, escaping every segment so an id carrying a slash, space, or other reserved character cannot alter the request path. With no segments it returns base unchanged.

func Paginate added in v0.2.0

func Paginate[T any, O ~func(*Query)](
	ctx context.Context,
	opts []O,
	withCursor func(string) O,
	list func(ctx context.Context, opts ...O) (*Page[T], error),
) iter.Seq2[*T, error]

Paginate turns a resource's List method into a range-over-func sequence, carrying the caller's options onto every page and overriding the pagination cursor with each page's next_starting_after.

It collapses the near-identical ListIter closures the GET-with-options resources used to carry: pass the caller's options, the option constructor that sets the cursor (WithStartingAfter), and the List method itself. The caller's option slice is never mutated. All the termination guards live in Iterate, which this delegates to.

func PatchResult added in v0.2.0

func PatchResult[T any](ctx context.Context, c *Client, path string, payload any) (*T, error)

PatchResult performs a PATCH with payload and decodes the response into a fresh T. It returns a nil *T on any error.

func PostResult added in v0.2.0

func PostResult[T any](ctx context.Context, c *Client, path string, payload any) (*T, error)

PostResult performs a POST with payload and decodes the response into a fresh T. It returns a nil *T on any error.

func Ptr

func Ptr[T any](v T) *T

Ptr returns a pointer to v.

It is a convenience for populating the optional, pointer-typed fields the API models as nullable: instantly.Ptr(true) yields a *bool without a named local.

Types

type APIError

type APIError struct {
	// StatusCode is the HTTP status code of the response. It is 200 when the
	// error arrived inside an otherwise successful response.
	StatusCode int64 `json:"statusCode,omitempty"`

	// Code is the machine-readable error code, such as ACC_AUTH_ERROR for an
	// error delivered at HTTP 200, or Unauthorized for a 4xx envelope.
	Code string `json:"error,omitempty"`

	// Message is the human-readable error detail, when the API provides one.
	Message string `json:"message,omitempty"`
}

APIError represents an error returned by the Instantly.ai API.

It covers both wire shapes the API uses: a 4xx envelope carrying {statusCode, error, message}, and an error code delivered inside an HTTP 200 body as {"error": "ACC_AUTH_ERROR"}. Both are returned as an error, so err != nil catches every real failure.

Callers can inspect the code with errors.As:

var apiErr *instantly.APIError
if errors.As(err, &apiErr) && apiErr.Code == instantly.ErrCodeAccountAuthError {
	// the sending account failed to authenticate
}

func (*APIError) Error

func (e *APIError) Error() string

Error returns a readable description of the API error for both wire shapes.

type Client

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

Client provides a connection to the Instantly.ai V2 API.

Every request is authenticated with a single V2 API key sent as a bearer token. V2 keys are distinct from V1 keys and are not interchangeable.

A Client is safe for concurrent use by multiple goroutines. It is immutable after construction: configure it once with the functional options passed to NewClient rather than mutating it afterwards.

The low-level request plumbing (Do, Get, Post, Patch, Put, Delete, DoRaw) is exported so the resource subpackages — which live in their own packages — can build on it, and so consumers keep a forward-compatible escape hatch for any endpoint the typed resource packages do not yet wrap.

See https://developer.instantly.ai/getting-started/authorization

func NewClient

func NewClient(apiKey string, opts ...ClientOption) *Client

NewClient builds a Client from the provided Instantly V2 API key.

Without options it uses a default HTTP client and the default API base URL. Pass functional options such as WithHTTPClient or WithBaseURL to customize it.

Example

ExampleNewClient constructs a client once and hands it to a resource service.

package main

import (
	"fmt"

	"github.com/mrz1836/go-instantly"
	"github.com/mrz1836/go-instantly/email"
)

func main() {
	client := instantly.NewClient("my-v2-api-key",
		instantly.WithUserAgent("my-app/1.0"),
	)

	svc := email.New(client)
	_ = svc

	fmt.Println("email service ready")
}
Output:
email service ready

func (*Client) Delete

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

Delete performs a DELETE request and decodes the response into out.

Endpoints that delete with a request body are rare; call Do with http.MethodDelete and a payload directly for those.

func (*Client) Do

func (c *Client) Do(ctx context.Context, method, path string, payload, out any) error

Do performs an API request and decodes the response into out.

It is the single choke point every resource method routes through: it marshals the payload, authenticates the request, and converts both API error wire shapes into a returned error before out is ever populated. A nil payload sends no body, and a nil out skips response decoding.

func (*Client) DoRaw

func (c *Client) DoRaw(ctx context.Context, method, path string, payload any) ([]byte, error)

DoRaw performs an API request and returns the raw response body.

It runs the same error handling as Do — a failing status or an error embedded in a success body is returned as an error — but hands back the undecoded bytes for endpoints that answer with a non-JSON payload, such as a CSV export.

func (*Client) Get

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

Get performs a GET request and decodes the response into out.

func (*Client) Patch

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

Patch performs a PATCH request with the given payload and decodes the response into out.

func (*Client) Post

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

Post performs a POST request with the given payload and decodes the response into out.

func (*Client) Put

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

Put performs a PUT request with the given payload and decodes the response into out.

type ClientOption

type ClientOption func(*Client)

ClientOption configures a Client during construction.

Options are applied in order, so a later option overrides an earlier one that sets the same field.

func WithBaseURL

func WithBaseURL(baseURL string) ClientOption

WithBaseURL overrides the root API endpoint, chiefly to point the client at a mock server in tests. An empty value falls back to the default base URL.

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) ClientOption

WithHTTPClient sets the HTTP client used to execute requests, which is how a caller supplies a custom transport, proxy, or timeout.

func WithHTTPHeader

func WithHTTPHeader(key, value string) ClientOption

WithHTTPHeader adds an extra header sent on every request.

The header is merged onto each request before the mandatory Accept, Content-Type, and Authorization headers, so it cannot override them. Calling it more than once with the same key adds multiple values for that header.

func WithUserAgent

func WithUserAgent(userAgent string) ClientOption

WithUserAgent sets the User-Agent header sent on every request.

type CountResponse added in v0.2.0

type CountResponse struct {
	// Count is the counted value the endpoint reported.
	Count int64 `json:"count"`
}

CountResponse is the {"count":N} wrapper the counting endpoints return.

It is the single decode target the launched-campaign, unread-email, and bulk-delete counts share, in place of a per-resource clone.

type FetchPage

type FetchPage[T any] func(ctx context.Context, cursor string) (items []T, next string, err error)

FetchPage fetches a single page of a cursor-paginated list.

It returns the items on the page, the cursor for the following page (empty on the last page), and any error. The cursor passed in is empty on the first call and is the previous page's next cursor thereafter.

type Page added in v0.2.0

type Page[T any] struct {
	// Items are the resources on this page.
	Items []T `json:"items"`

	// NextStartingAfter is the cursor for the following page, and is empty on
	// the last page.
	NextStartingAfter string `json:"next_starting_after,omitempty"`
}

Page is one page of a cursor-paginated list, shared by every resource.

Each resource package aliases its ListResponse to a Page of its own item type (type ListResponse = instantly.Page[Campaign]). Because the alias is an identical type rather than a distinct defined one, the generic helpers below — Paginate in particular — accept a resource's List method directly.

type Query

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

Query accumulates the query parameters a list request sends.

Resource packages expose their own typed ListOption values that write into a Query, which keeps every query key and value compile-time checked while sharing a single accumulator and encoder across all 28 resources. Setting the same key twice keeps the last value.

func ApplyOptions added in v0.2.0

func ApplyOptions[O ~func(*Query)](opts ...O) *Query

ApplyOptions builds a Query from the supplied typed per-resource options.

Every resource defines its own ListOption as func(*Query); the ~func(*Query) constraint accepts any of them, so this single helper replaces the identical apply loop each List method used to carry. A nil option is skipped rather than invoked.

func NewQuery

func NewQuery() *Query

NewQuery returns an empty Query ready for options to write into.

func SetEnum

func SetEnum[E ~string](q *Query, key string, value E) *Query

SetEnum sets a string-backed enum query parameter.

It is a free function rather than a method because Go methods cannot take type parameters; resource options call it as instantly.SetEnum(q, key, value).

func (*Query) AddString

func (q *Query) AddString(key, value string) *Query

AddString appends a string value to a query parameter, keeping any values already set. It is how a repeated array parameter (key=a&key=b) is built.

func (*Query) Encode

func (q *Query) Encode() string

Encode renders the accumulated parameters as a URL-encoded query string.

func (*Query) Get

func (q *Query) Get(key string) string

Get returns the first value set for key, or the empty string when key is unset. It is chiefly a testing convenience for asserting what an option wrote.

func (*Query) Len

func (q *Query) Len() int

Len reports how many distinct query parameters have been set. Tests use it as a completeness guard, asserting an option renders exactly one parameter.

func (*Query) Path

func (q *Query) Path(base string) string

Path appends the encoded parameters to base, returning the bare base when no parameter has been set so an unfiltered request never carries an empty "?".

func (*Query) SetBool

func (q *Query) SetBool(key string, value bool) *Query

SetBool sets a boolean query parameter, rendered as "true" or "false".

func (*Query) SetInt

func (q *Query) SetInt(key string, value int) *Query

SetInt sets an integer query parameter.

func (*Query) SetString

func (q *Query) SetString(key, value string) *Query

SetString sets a string query parameter, replacing any existing value.

type SortOrder

type SortOrder string

SortOrder is the direction results are sorted in. It is shared across the resource packages because more than one list endpoint sorts the same way.

const (
	// SortOrderAsc sorts results oldest first.
	SortOrderAsc SortOrder = "asc"

	// SortOrderDesc sorts results newest first.
	SortOrderDesc SortOrder = "desc"
)

The directions results can be sorted in.

Directories

Path Synopsis
Package account provides typed access to the Instantly.ai V2 Account API.
Package account provides typed access to the Instantly.ai V2 Account API.
Package accountcampaign provides typed access to the Instantly.ai V2 account-campaign-mappings endpoint: the campaigns a sending account belongs to.
Package accountcampaign provides typed access to the Instantly.ai V2 account-campaign-mappings endpoint: the campaigns a sending account belongs to.
Package apikey provides typed access to the Instantly.ai V2 API Key API.
Package apikey provides typed access to the Instantly.ai V2 API Key API.
Package auditlog provides typed access to the Instantly.ai V2 Audit Log API.
Package auditlog provides typed access to the Instantly.ai V2 Audit Log API.
Package backgroundjob provides typed access to the Instantly.ai V2 Background Job API.
Package backgroundjob provides typed access to the Instantly.ai V2 Background Job API.
Package blocklist provides typed access to the Instantly.ai V2 Block List Entry API.
Package blocklist provides typed access to the Instantly.ai V2 Block List Entry API.
Package campaign provides typed access to the Instantly.ai V2 Campaign API.
Package campaign provides typed access to the Instantly.ai V2 Campaign API.
Package crm provides typed access to the Instantly.ai V2 CRM Actions API.
Package crm provides typed access to the Instantly.ai V2 CRM Actions API.
Package customtag provides typed access to the Instantly.ai V2 Custom Tag API.
Package customtag provides typed access to the Instantly.ai V2 Custom Tag API.
Package customtagmapping provides typed access to the Instantly.ai V2 Custom Tag Mapping API.
Package customtagmapping provides typed access to the Instantly.ai V2 Custom Tag Mapping API.
Package dfy provides typed access to the Instantly.ai V2 Done-For-You (DFY) Email Account Order API.
Package dfy provides typed access to the Instantly.ai V2 Done-For-You (DFY) Email Account Order API.
Package email provides typed access to the Instantly.ai V2 Email API.
Package email provides typed access to the Instantly.ai V2 Email API.
Package emailverification provides typed access to the Instantly.ai V2 Email Verification API.
Package emailverification provides typed access to the Instantly.ai V2 Email Verification API.
Package main is an example of how to use the Instantly.ai V2 Go SDK.
Package main is an example of how to use the Instantly.ai V2 Go SDK.
Package inboxanalytics provides typed access to the Instantly.ai V2 Inbox Placement Analytics API.
Package inboxanalytics provides typed access to the Instantly.ai V2 Inbox Placement Analytics API.
Package inboxreport provides typed access to the Instantly.ai V2 Inbox Placement blacklist and SpamAssassin report API.
Package inboxreport provides typed access to the Instantly.ai V2 Inbox Placement blacklist and SpamAssassin report API.
Package inboxtest provides typed access to the Instantly.ai V2 Inbox Placement Test API.
Package inboxtest provides typed access to the Instantly.ai V2 Inbox Placement Test API.
internal
instantlytest
Package instantlytest provides the shared test harness for the go-instantly SDK: a small HTTP mock router, a reusable testify suite, and assertion helpers.
Package instantlytest provides the shared test harness for the go-instantly SDK: a small HTTP mock router, a reusable testify suite, and assertion helpers.
Package lead provides typed access to the Instantly.ai V2 Lead API.
Package lead provides typed access to the Instantly.ai V2 Lead API.
Package leadlabel provides typed access to the Instantly.ai V2 Lead Label API.
Package leadlabel provides typed access to the Instantly.ai V2 Lead Label API.
Package leadlist provides typed access to the Instantly.ai V2 Lead List API.
Package leadlist provides typed access to the Instantly.ai V2 Lead List API.
Package oauth provides typed access to the Instantly.ai V2 OAuth API.
Package oauth provides typed access to the Instantly.ai V2 OAuth API.
Package subsequence provides typed access to the Instantly.ai V2 Campaign Subsequence API.
Package subsequence provides typed access to the Instantly.ai V2 Campaign Subsequence API.
Package supersearch provides typed access to the Instantly.ai V2 SuperSearch Enrichment API.
Package supersearch provides typed access to the Instantly.ai V2 SuperSearch Enrichment API.
Package webhook provides typed access to the Instantly.ai V2 Webhook API.
Package webhook provides typed access to the Instantly.ai V2 Webhook API.
Package webhookevent provides typed access to the Instantly.ai V2 Webhook Event API.
Package webhookevent provides typed access to the Instantly.ai V2 Webhook Event API.
Package workspace provides typed access to the Instantly.ai V2 Workspace API.
Package workspace provides typed access to the Instantly.ai V2 Workspace API.
Package workspacebilling provides typed access to the Instantly.ai V2 Workspace Billing API.
Package workspacebilling provides typed access to the Instantly.ai V2 Workspace Billing API.
Package workspacegroup provides typed access to the Instantly.ai V2 Workspace Group Member API.
Package workspacegroup provides typed access to the Instantly.ai V2 Workspace Group Member API.
Package workspacemember provides typed access to the Instantly.ai V2 Workspace Member API.
Package workspacemember provides typed access to the Instantly.ai V2 Workspace Member API.

Jump to

Keyboard shortcuts

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