Skip to content

Repository files navigation

Email Funnel AI — Go SDK

Official Go client for the Email Funnel AI integration API. Connect with your project key and secret, then call typed, service-oriented methods — no manual URLs, headers, or JSON plumbing.

  • Standard library only (net/http + encoding/json) — zero dependencies
  • Idiomatic services: client.Contacts.Sync(ctx, req) returning (Data, error)
  • Typed error model (*APIError) with status, error_type, and 422 field messages
  • Injectable transport (HTTPClient) — *http.Client satisfies it directly
  • Full coverage of all 26 endpoints

Installation

go get github.com/emailfunnelai/sdk-go
import emailfunnelai "github.com/emailfunnelai/sdk-go"

Quick start

package main

import (
	"context"
	"fmt"
	"log"

	emailfunnelai "github.com/emailfunnelai/sdk-go"
)

func main() {
	ctx := context.Background()

	// Base URL defaults to https://app.emailfunnel.ai — override only for staging/local.
	client := emailfunnelai.New("pk_your_project_key", "sk_your_secret_key")

	// 1. Confirm your credentials
	if _, err := client.Validate(ctx); err != nil {
		log.Fatal(err)
	}

	// 2. Get or create a list
	list, err := client.Lists.Create(ctx, emailfunnelai.ListCreateRequest{Name: "Newsletter signups"})
	if err != nil {
		log.Fatal(err)
	}

	var created struct {
		ID string `json:"id"`
	}
	if err := list.Into(&created); err != nil {
		log.Fatal(err)
	}

	// 3. Sync a contact into it
	_, err = client.Contacts.Sync(ctx, emailfunnelai.ContactSyncRequest{
		Contact:       map[string]any{"email": "jane@example.com", "source_type": "custom_saas"},
		ContactListID: created.ID,
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("done")
}

Every call returns the unwrapped data payload as a Data value. Decode it into your own type with data.Into(&v), or read the raw JSON with data.String().

Usage

Every group is reached from the client as client.<Service>.<Method>(ctx, …).

Contacts

// Single contact
client.Contacts.Sync(ctx, emailfunnelai.ContactSyncRequest{
	Contact:       map[string]any{"email": "jane@example.com", "source_type": "app"},
	ContactListID: "42",
})

// Bulk (up to 500; the server queues automatically above 100 rows)
client.Contacts.Bulk(ctx, emailfunnelai.BulkSyncRequest{
	Contacts:      []map[string]any{{"email": "a@example.com"}},
	ContactListID: "42",
	SourceType:    "import",
	Async:         true, // force queued processing
})

// Real-time webhook event
client.Contacts.Webhook(ctx, emailfunnelai.WebhookRequest{
	Event:         "order.completed",
	Data:          map[string]any{"email": "a@example.com"},
	ContactListID: "42",
})

Lists

client.Lists.All(ctx)
client.Lists.Create(ctx, emailfunnelai.ListCreateRequest{Name: "VIP", Description: "High-value buyers"})
client.Lists.Find(ctx, "42")

Bindings

client.Bindings.All(ctx)
client.Bindings.Create(ctx, emailfunnelai.BindingCreateRequest{SourceType: "custom_crm", ContactListID: "42"})
client.Bindings.Find(ctx, "5")
client.Bindings.Update(ctx, "5", emailfunnelai.BindingUpdateRequest{SyncEnabled: emailfunnelai.Bool(false)})
client.Bindings.Delete(ctx, "5")
client.Bindings.Status(ctx, "5", emailfunnelai.BindingStatusRequest{Status: "completed", ErrorsCount: emailfunnelai.Int(0)})

Field mappings

client.FieldMappings.Config(ctx, "custom_saas")
client.FieldMappings.ForBinding("5").Get(ctx)
client.FieldMappings.ForBinding("5").Update(ctx, map[string]string{"email": "Email"})
client.FieldMappings.ForBinding("5").Reset(ctx)

Auto-tagging

client.AutoTagging.Rules(ctx, "custom_saas")
client.AutoTagging.Preview(ctx, "custom_saas", map[string]any{"plan": "pro"})

Analytics

client.Analytics.Dashboard(ctx)
client.Analytics.Heatmap(ctx, emailfunnelai.HeatmapOptions{Range: 30, EmailType: "campaign", Timezone: "America/New_York"})
client.Analytics.Funnels(ctx)
client.Analytics.Campaigns(ctx)
client.Analytics.Forms(ctx)

SSO

client.SSO.Generate(ctx, "admin@example.com")
client.SSO.TeamMembers(ctx)

Responses & errors

Successful calls return the unwrapped data payload. Any error response returns an *APIError; use AsAPIError to inspect it:

data, err := client.Contacts.Sync(ctx, req)
if err != nil {
	if apiErr, ok := emailfunnelai.AsAPIError(err); ok {
		apiErr.Status     // 422
		apiErr.ErrorType  // "validation_error"
		apiErr.Messages   // map[string][]string — set on 422
		apiErr.RetryAfter // int seconds — set on 429 rate limits
	}
	// otherwise a transport/decoding error
}

Branch on ErrorType for specific conditions — e.g. a contact list that has been deactivated rejects new members with a 409 list_inactive:

if _, err := client.Contacts.Sync(ctx, req); err != nil {
	if apiErr, ok := emailfunnelai.AsAPIError(err); ok && apiErr.ErrorType == "list_inactive" {
		// The target list is inactive — reactivate it or pick another list.
	}
}

Common error_type values

error_type Status Meaning
invalid_credentials 401 Missing/invalid project key or secret
inactive_project 403 The connected project is inactive
validation_error 422 Request body failed validation (Messages set)
invalid_email / suppressed 422 Email is undeliverable or suppressed
list_inactive 409 Target contact list is inactive and rejects new members
rate_limit_exceeded 429 1000 req/hour cap hit (RetryAfter set)
sync_failed 500 Unexpected sync failure

Custom transport & base URL

import "net/http"

// Point at a local dev server
client := emailfunnelai.New("pk", "sk", emailfunnelai.WithBaseURL("http://localhost:8000"))

// Inject a pre-configured *http.Client (timeouts, proxies, transport)
httpClient := &http.Client{Timeout: 30 * time.Second}
client = emailfunnelai.New("pk", "sk", emailfunnelai.WithHTTPClient(httpClient))

Any type implementing HTTPClient (a single Do(*http.Request) (*http.Response, error) method) can be injected — used by this package's own test suite for fast, offline tests.

Testing

go test ./...

License

MIT © Email Funnel AI. Authored by Email Funnel AI and Ratul Hasan.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages