← Back to API Dashboard

🐹 Go Module

Enterprise-grade Voice, SMS, Email & AI API for Go microservices and cloud applications

🚧 Coming Soon - Use REST API for now

📦 Installation

The Go module will be available when released:

# Coming soon!
go get github.com/team-connect/go

# For now, use standard library net/http
# No external dependencies needed!
🚀 Cloud Native: Built for microservices, Kubernetes, Docker, and cloud deployments. Zero external dependencies, production-ready with context support and graceful shutdowns.

🚀 Quick Start

Here's how you'll use the Go module once it's available:

// Future module usage
package main

import (
    "context"
    "fmt"
    "log"
    
    "github.com/team-connect/go/teamconnect"
)

func main() {
    // Initialize with your API key
    client := teamconnect.NewClient("tc_live_your_api_key_here")
    
    ctx := context.Background()
    
    // Make a voice call
    callResult, err := client.Voice.MakeCall(ctx, &teamconnect.CallRequest{
        To:      "+447123456789",
        Message: "Hello from Team Connect!",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Call initiated: %s\n", callResult.CallID)
    
    // Send an SMS
    smsResult, err := client.SMS.Send(ctx, &teamconnect.SMSRequest{
        To:      "+447123456789",
        Message: "Your verification code is 123456",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("SMS sent: %s\n", smsResult.MessageID)
    
    // Send an email
    emailResult, err := client.Email.Send(ctx, &teamconnect.EmailRequest{
        To:      "customer@example.com",
        Subject: "Welcome to our service",
        HTML:    "

Welcome!

Thanks for signing up.

", }) if err != nil { log.Fatal(err) } fmt.Printf("Email sent: %s\n", emailResult.MessageID) // AI Chat aiResult, err := client.AI.Chat(ctx, &teamconnect.ChatRequest{ Messages: []teamconnect.Message{ {Role: "system", Content: "You are a helpful assistant."}, {Role: "user", Content: "Hello!"}, }, }) if err != nil { log.Fatal(err) } fmt.Printf("AI Response: %s\n", aiResult.Response) }

🔐 Current Implementation (REST API)

Until the module is ready, use our REST API with Go's standard library:

// Standard library implementation
package main

import (
    "bytes"
    "context"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "time"
)

const BaseURL = "https://us-central1-customerservice-2156c.cloudfunctions.net"

type TeamConnectClient struct {
    APIKey     string
    HTTPClient *http.Client
}

type APIRequest struct {
    Service string      `json:"service"`
    Action  string      `json:"action"`
    Data    interface{} `json:"data"`
    APIKey  string      `json:"api_key"`
}

type APIResponse struct {
    Success bool                   `json:"success"`
    Result  map[string]interface{} `json:"result,omitempty"`
    Error   string                 `json:"error,omitempty"`
    Billing map[string]interface{} `json:"billing,omitempty"`
}

func NewTeamConnectClient(apiKey string) *TeamConnectClient {
    return &TeamConnectClient{
        APIKey: apiKey,
        HTTPClient: &http.Client{
            Timeout: 30 * time.Second,
        },
    }
}

func (c *TeamConnectClient) MakeRequest(ctx context.Context, service, action string, data interface{}) (*APIResponse, error) {
    reqBody := APIRequest{
        Service: service,
        Action:  action,
        Data:    data,
        APIKey:  c.APIKey,
    }

    jsonData, err := json.Marshal(reqBody)
    if err != nil {
        return nil, fmt.Errorf("marshal request: %w", err)
    }

    req, err := http.NewRequestWithContext(ctx, "POST", BaseURL+"/executeAPI", bytes.NewBuffer(jsonData))
    if err != nil {
        return nil, fmt.Errorf("create request: %w", err)
    }

    req.Header.Set("Content-Type", "application/json")

    resp, err := c.HTTPClient.Do(req)
    if err != nil {
        return nil, fmt.Errorf("do request: %w", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, fmt.Errorf("read response: %w", err)
    }

    var apiResp APIResponse
    if err := json.Unmarshal(body, &apiResp); err != nil {
        return nil, fmt.Errorf("unmarshal response: %w", err)
    }

    // Handle HTTP errors
    switch resp.StatusCode {
    case 401:
        return nil, fmt.Errorf("invalid API key")
    case 402:
        return nil, fmt.Errorf("insufficient credits: %s", apiResp.Error)
    case 429:
        return nil, fmt.Errorf("rate limit exceeded")
    case 200:
        if !apiResp.Success {
            return nil, fmt.Errorf("API error: %s", apiResp.Error)
        }
        return &apiResp, nil
    default:
        return nil, fmt.Errorf("HTTP error: %d", resp.StatusCode)
    }
}

func main() {
    client := NewTeamConnectClient("tc_live_your_api_key_here")
    ctx := context.Background()

    // Example usage
    resp, err := client.MakeRequest(ctx, "voice", "make_call", map[string]interface{}{
        "to":      "+447123456789",
        "message": "Hello from Go!",
    })
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Printf("Success: %+v\n", resp.Result)
}
// Typed client with proper structs
package main

import (
    "context"
    "fmt"
    "time"
)

// Request types
type CallRequest struct {
    To         string `json:"to"`
    Message    string `json:"message"`
    From       string `json:"from,omitempty"`
    Voice      string `json:"voice,omitempty"`
    WebhookURL string `json:"webhook_url,omitempty"`
}

type SMSRequest struct {
    To      string `json:"to"`
    Message string `json:"message"`
    From    string `json:"from,omitempty"`
}

type EmailRequest struct {
    To       string `json:"to"`
    Subject  string `json:"subject"`
    HTML     string `json:"html"`
    FromName string `json:"from_name,omitempty"`
}

type ChatMessage struct {
    Role    string `json:"role"`
    Content string `json:"content"`
}

type ChatRequest struct {
    Messages []ChatMessage `json:"messages"`
    Model    string        `json:"model,omitempty"`
}

// Response types
type CallResponse struct {
    CallID            string    `json:"call_id"`
    Status            string    `json:"status"`
    To                string    `json:"to"`
    From              string    `json:"from"`
    EstimatedDuration int       `json:"estimated_duration"`
    CreatedAt         time.Time `json:"created_at"`
}

type SMSResponse struct {
    MessageID string    `json:"message_id"`
    Status    string    `json:"status"`
    To        string    `json:"to"`
    From      string    `json:"from"`
    CreatedAt time.Time `json:"created_at"`
}

type EmailResponse struct {
    MessageID string    `json:"message_id"`
    Status    string    `json:"status"`
    To        string    `json:"to"`
    Subject   string    `json:"subject"`
    CreatedAt time.Time `json:"created_at"`
}

type ChatResponse struct {
    Response   string `json:"response"`
    Model      string `json:"model"`
    TokensUsed int    `json:"tokens_used"`
}

type BillingInfo struct {
    Cost                      float64 `json:"cost"`
    CostFormatted            string  `json:"costFormatted"`
    Service                  string  `json:"service"`
    Action                   string  `json:"action"`
    CreditsRemaining         float64 `json:"creditsRemaining"`
    CreditsRemainingFormatted string  `json:"creditsRemainingFormatted"`
}

// Typed service methods
func (c *TeamConnectClient) MakeCall(ctx context.Context, req *CallRequest) (*CallResponse, *BillingInfo, error) {
    resp, err := c.MakeRequest(ctx, "voice", "make_call", req)
    if err != nil {
        return nil, nil, err
    }

    var callResp CallResponse
    if err := mapToStruct(resp.Result, &callResp); err != nil {
        return nil, nil, fmt.Errorf("decode call response: %w", err)
    }

    var billing BillingInfo
    if resp.Billing != nil {
        mapToStruct(resp.Billing, &billing)
    }

    return &callResp, &billing, nil
}

func (c *TeamConnectClient) SendSMS(ctx context.Context, req *SMSRequest) (*SMSResponse, *BillingInfo, error) {
    resp, err := c.MakeRequest(ctx, "sms", "send", req)
    if err != nil {
        return nil, nil, err
    }

    var smsResp SMSResponse
    if err := mapToStruct(resp.Result, &smsResp); err != nil {
        return nil, nil, fmt.Errorf("decode SMS response: %w", err)
    }

    var billing BillingInfo
    if resp.Billing != nil {
        mapToStruct(resp.Billing, &billing)
    }

    return &smsResp, &billing, nil
}

func (c *TeamConnectClient) SendEmail(ctx context.Context, req *EmailRequest) (*EmailResponse, *BillingInfo, error) {
    resp, err := c.MakeRequest(ctx, "email", "send", req)
    if err != nil {
        return nil, nil, err
    }

    var emailResp EmailResponse
    if err := mapToStruct(resp.Result, &emailResp); err != nil {
        return nil, nil, fmt.Errorf("decode email response: %w", err)
    }

    var billing BillingInfo
    if resp.Billing != nil {
        mapToStruct(resp.Billing, &billing)
    }

    return &emailResp, &billing, nil
}

func (c *TeamConnectClient) ChatAI(ctx context.Context, req *ChatRequest) (*ChatResponse, *BillingInfo, error) {
    if req.Model == "" {
        req.Model = "gpt-4"
    }

    resp, err := c.MakeRequest(ctx, "ai", "chat", req)
    if err != nil {
        return nil, nil, err
    }

    var chatResp ChatResponse
    if err := mapToStruct(resp.Result, &chatResp); err != nil {
        return nil, nil, fmt.Errorf("decode chat response: %w", err)
    }

    var billing BillingInfo
    if resp.Billing != nil {
        mapToStruct(resp.Billing, &billing)
    }

    return &chatResp, &billing, nil
}

// Helper function to map interface{} to struct
func mapToStruct(data interface{}, target interface{}) error {
    // This is a simplified version - in production, use a proper library
    // or implement proper type conversion
    return nil // Implementation details omitted for brevity
}

// Example usage
func main() {
    client := NewTeamConnectClient("tc_live_your_api_key_here")
    ctx := context.Background()

    // Make a call with typed request/response
    callResp, billing, err := client.MakeCall(ctx, &CallRequest{
        To:      "+447123456789",
        Message: "Hello from Go with types!",
        Voice:   "Polly.Amy",
    })
    if err != nil {
        fmt.Printf("Call error: %v\n", err)
        return
    }

    fmt.Printf("✅ Call initiated successfully!\n")
    fmt.Printf("Call ID: %s\n", callResp.CallID)
    fmt.Printf("Status: %s\n", callResp.Status)
    fmt.Printf("Cost: %s\n", billing.CostFormatted)

    if billing.CreditsRemaining < 500 {
        fmt.Printf("⚠️ Low credits remaining: %s\n", billing.CreditsRemainingFormatted)
    }
}
// Concurrent operations with goroutines
package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

// Concurrent batch operations
type BatchResult struct {
    Index   int
    Success bool
    Result  interface{}
    Error   error
}

func (c *TeamConnectClient) MakeCallsBatch(ctx context.Context, requests []*CallRequest) []BatchResult {
    results := make([]BatchResult, len(requests))
    var wg sync.WaitGroup
    
    // Limit concurrent requests to avoid rate limits
    semaphore := make(chan struct{}, 5) // Max 5 concurrent requests
    
    for i, req := range requests {
        wg.Add(1)
        go func(index int, request *CallRequest) {
            defer wg.Done()
            
            // Acquire semaphore
            semaphore <- struct{}{}
            defer func() { <-semaphore }()
            
            resp, _, err := c.MakeCall(ctx, request)
            results[index] = BatchResult{
                Index:   index,
                Success: err == nil,
                Result:  resp,
                Error:   err,
            }
        }(i, req)
    }
    
    wg.Wait()
    return results
}

func (c *TeamConnectClient) SendSMSBatch(ctx context.Context, requests []*SMSRequest) []BatchResult {
    results := make([]BatchResult, len(requests))
    var wg sync.WaitGroup
    semaphore := make(chan struct{}, 10) // SMS can handle more concurrent requests
    
    for i, req := range requests {
        wg.Add(1)
        go func(index int, request *SMSRequest) {
            defer wg.Done()
            
            semaphore <- struct{}{}
            defer func() { <-semaphore }()
            
            resp, _, err := c.SendSMS(ctx, request)
            results[index] = BatchResult{
                Index:   index,
                Success: err == nil,
                Result:  resp,
                Error:   err,
            }
        }(i, req)
    }
    
    wg.Wait()
    return results
}

// Rate-limited client with retry logic
type RateLimitedClient struct {
    *TeamConnectClient
    rateLimiter chan struct{}
}

func NewRateLimitedClient(apiKey string, requestsPerSecond int) *RateLimitedClient {
    client := NewTeamConnectClient(apiKey)
    rateLimiter := make(chan struct{}, requestsPerSecond)
    
    // Fill rate limiter
    go func() {
        ticker := time.NewTicker(time.Second)
        defer ticker.Stop()
        
        for {
            select {
            case <-ticker.C:
                // Reset rate limiter each second
                for len(rateLimiter) < requestsPerSecond {
                    select {
                    case rateLimiter <- struct{}{}:
                    default:
                        goto next
                    }
                }
                next:
            }
        }
    }()
    
    return &RateLimitedClient{
        TeamConnectClient: client,
        rateLimiter:       rateLimiter,
    }
}

func (c *RateLimitedClient) MakeCallWithRetry(ctx context.Context, req *CallRequest, maxRetries int) (*CallResponse, *BillingInfo, error) {
    var lastErr error
    
    for attempt := 0; attempt <= maxRetries; attempt++ {
        // Wait for rate limit
        select {
        case <-c.rateLimiter:
        case <-ctx.Done():
            return nil, nil, ctx.Err()
        }
        
        resp, billing, err := c.MakeCall(ctx, req)
        if err == nil {
            return resp, billing, nil
        }
        
        lastErr = err
        
        // Don't retry on certain errors
        if isNonRetryableError(err) {
            break
        }
        
        // Exponential backoff
        if attempt < maxRetries {
            waitTime := time.Duration(1<= len(substr) && s[:len(substr)] == substr
}

// Example usage with concurrency
func main() {
    client := NewRateLimitedClient("tc_live_your_api_key_here", 5) // 5 requests per second
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
    defer cancel()

    // Batch SMS sending
    smsRequests := []*SMSRequest{
        {To: "+447123456789", Message: "Hello customer 1!"},
        {To: "+447123456790", Message: "Hello customer 2!"},
        {To: "+447123456791", Message: "Hello customer 3!"},
        {To: "+447123456792", Message: "Hello customer 4!"},
        {To: "+447123456793", Message: "Hello customer 5!"},
    }

    fmt.Println("Sending batch SMS...")
    results := client.SendSMSBatch(ctx, smsRequests)

    successCount := 0
    for _, result := range results {
        if result.Success {
            successCount++
            fmt.Printf("✅ SMS %d sent successfully\n", result.Index+1)
        } else {
            fmt.Printf("❌ SMS %d failed: %v\n", result.Index+1, result.Error)
        }
    }

    fmt.Printf("Batch complete: %d/%d successful\n", successCount, len(smsRequests))

    // Single call with retry
    fmt.Println("\nMaking call with retry...")
    callResp, billing, err := client.MakeCallWithRetry(ctx, &CallRequest{
        To:      "+447123456789",
        Message: "Hello with retry logic!",
    }, 3)

    if err != nil {
        fmt.Printf("Call failed after retries: %v\n", err)
        return
    }

    fmt.Printf("✅ Call successful: %s\n", callResp.CallID)
    fmt.Printf("💰 Cost: %s\n", billing.CostFormatted)
}

📞 Voice Calls

Make AI-powered voice calls with Go's performance and reliability:

package main

import (
    "context"
    "fmt"
    "log"
    "time"
)

// Voice call helper with context and timeout
func makeCall(client *TeamConnectClient, to, message string, options map[string]interface{}) error {
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    data := map[string]interface{}{
        "to":      to,
        "message": message,
    }

    // Add optional parameters
    for key, value := range options {
        data[key] = value
    }

    resp, err := client.MakeRequest(ctx, "voice", "make_call", data)
    if err != nil {
        return fmt.Errorf("call failed: %w", err)
    }

    if !resp.Success {
        return fmt.Errorf("call failed: %s", resp.Error)
    }

    fmt.Printf("✅ Call initiated successfully!\n")
    if callID, ok := resp.Result["call_id"].(string); ok {
        fmt.Printf("Call ID: %s\n", callID)
    }
    if status, ok := resp.Result["status"].(string); ok {
        fmt.Printf("Status: %s\n", status)
    }
    if billing := resp.Billing; billing != nil {
        if cost, ok := billing["costFormatted"].(string); ok {
            fmt.Printf("Cost: %s\n", cost)
        }
        if remaining, ok := billing["creditsRemainingFormatted"].(string); ok {
            fmt.Printf("Credits remaining: %s\n", remaining)
        }
    }

    return nil
}

// Appointment confirmation system
type Appointment struct {
    ID           string
    CustomerName string
    CustomerPhone string
    ServiceType  string
    DateTime     time.Time
}

func sendAppointmentConfirmation(client *TeamConnectClient, appointment *Appointment) error {
    message := fmt.Sprintf(
        "Hi %s, this is confirming your %s appointment tomorrow at %s. Reply YES to confirm or NO to reschedule.",
        appointment.CustomerName,
        appointment.ServiceType,
        appointment.DateTime.Format("3:04 PM"),
    )

    return makeCall(client, appointment.CustomerPhone, message, map[string]interface{}{
        "voice": "Polly.Amy",
        "webhook_url": fmt.Sprintf("https://yourapp.com/webhooks/appointment/%s", appointment.ID),
    })
}

// Payment reminder system
type Invoice struct {
    ID           string
    CustomerName string
    CustomerPhone string
    Amount       float64
    PaymentURL   string
}

func sendPaymentReminder(client *TeamConnectClient, invoice *Invoice) error {
    message := fmt.Sprintf(
        "Hello %s, this is a friendly reminder that your payment of £%.2f is due. You can pay online at %s or call us back.",
        invoice.CustomerName,
        invoice.Amount,
        invoice.PaymentURL,
    )

    return makeCall(client, invoice.CustomerPhone, message, map[string]interface{}{})
}

func main() {
    client := NewTeamConnectClient("tc_live_your_api_key_here")

    // Example appointment confirmation
    appointment := &Appointment{
        ID:           "apt_123",
        CustomerName: "John Doe",
        CustomerPhone: "+447123456789",
        ServiceType:  "dental cleaning",
        DateTime:     time.Now().Add(24 * time.Hour),
    }

    if err := sendAppointmentConfirmation(client, appointment); err != nil {
        log.Printf("Failed to send appointment confirmation: %v", err)
    }

    // Example payment reminder
    invoice := &Invoice{
        ID:           "inv_456",
        CustomerName: "Jane Smith",
        CustomerPhone: "+447123456790",
        Amount:       125.50,
        PaymentURL:   "https://pay.example.com/inv_456",
    }

    if err := sendPaymentReminder(client, invoice); err != nil {
        log.Printf("Failed to send payment reminder: %v", err)
    }
}

💬 SMS Messages

Send SMS messages with Go's concurrent capabilities:

package main

import (
    "context"
    "crypto/rand"
    "fmt"
    "math/big"
    "sync"
    "time"
)

// SMS helper with context
func sendSMS(client *TeamConnectClient, to, message string, options map[string]interface{}) error {
    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    defer cancel()

    data := map[string]interface{}{
        "to":      to,
        "message": message,
    }

    for key, value := range options {
        data[key] = value
    }

    resp, err := client.MakeRequest(ctx, "sms", "send", data)
    if err != nil {
        return fmt.Errorf("SMS failed: %w", err)
    }

    if !resp.Success {
        return fmt.Errorf("SMS failed: %s", resp.Error)
    }

    fmt.Printf("✅ SMS sent successfully!\n")
    if messageID, ok := resp.Result["message_id"].(string); ok {
        fmt.Printf("Message ID: %s\n", messageID)
    }

    return nil
}

// 2FA system with concurrent sending
type TwoFactorAuth struct {
    client *TeamConnectClient
    codes  sync.Map // thread-safe map for storing codes
}

func NewTwoFactorAuth(client *TeamConnectClient) *TwoFactorAuth {
    return &TwoFactorAuth{
        client: client,
    }
}

func (tfa *TwoFactorAuth) GenerateCode() (string, error) {
    // Generate 6-digit code
    max := big.NewInt(900000)
    n, err := rand.Int(rand.Reader, max)
    if err != nil {
        return "", err
    }
    return fmt.Sprintf("%06d", n.Int64()+100000), nil
}

func (tfa *TwoFactorAuth) SendCode(phone, appName string) (string, error) {
    code, err := tfa.GenerateCode()
    if err != nil {
        return "", fmt.Errorf("generate code: %w", err)
    }

    // Store code with expiry (in production, use Redis or database)
    tfa.codes.Store(phone, map[string]interface{}{
        "code":      code,
        "expires":   time.Now().Add(5 * time.Minute),
        "attempts":  0,
    })

    message := fmt.Sprintf("Your %s verification code: %s", appName, code)
    
    if err := sendSMS(tfa.client, phone, message, nil); err != nil {
        tfa.codes.Delete(phone)
        return "", err
    }

    return code, nil
}

func (tfa *TwoFactorAuth) VerifyCode(phone, inputCode string) bool {
    value, exists := tfa.codes.Load(phone)
    if !exists {
        return false
    }

    codeData := value.(map[string]interface{})
    
    // Check expiry
    if time.Now().After(codeData["expires"].(time.Time)) {
        tfa.codes.Delete(phone)
        return false
    }

    // Check attempts
    attempts := codeData["attempts"].(int)
    if attempts >= 3 {
        tfa.codes.Delete(phone)
        return false
    }

    // Update attempts
    codeData["attempts"] = attempts + 1
    tfa.codes.Store(phone, codeData)

    // Verify code
    if codeData["code"].(string) == inputCode {
        tfa.codes.Delete(phone)
        return true
    }

    return false
}

// Order notification system
type Order struct {
    Number      string
    CustomerPhone string
    Status      string
    TrackingURL string
}

func sendOrderUpdates(client *TeamConnectClient, orders []Order) {
    var wg sync.WaitGroup
    semaphore := make(chan struct{}, 10) // Limit concurrent SMS

    for _, order := range orders {
        wg.Add(1)
        go func(o Order) {
            defer wg.Done()
            
            semaphore <- struct{}{}
            defer func() { <-semaphore }()

            message := fmt.Sprintf(
                "Your order #%s is %s. Track: %s",
                o.Number,
                o.Status,
                o.TrackingURL,
            )

            if err := sendSMS(client, o.CustomerPhone, message, nil); err != nil {
                fmt.Printf("Failed to send order update for %s: %v\n", o.Number, err)
            } else {
                fmt.Printf("Order update sent for %s\n", o.Number)
            }
        }(order)
    }

    wg.Wait()
}

func main() {
    client := NewTeamConnectClient("tc_live_your_api_key_here")

    // 2FA example
    tfa := NewTwoFactorAuth(client)
    
    code, err := tfa.SendCode("+447123456789", "Dad-Link")
    if err != nil {
        fmt.Printf("Failed to send 2FA code: %v\n", err)
        return
    }
    
    fmt.Printf("2FA code sent: %s\n", code)
    
    // Simulate verification
    isValid := tfa.VerifyCode("+447123456789", code)
    fmt.Printf("Code verification: %t\n", isValid)

    // Batch order updates
    orders := []Order{
        {Number: "ORD001", CustomerPhone: "+447123456789", Status: "shipped", TrackingURL: "https://track.me/ORD001"},
        {Number: "ORD002", CustomerPhone: "+447123456790", Status: "delivered", TrackingURL: "https://track.me/ORD002"},
        {Number: "ORD003", CustomerPhone: "+447123456791", Status: "processing", TrackingURL: "https://track.me/ORD003"},
    }

    fmt.Println("Sending order updates...")
    sendOrderUpdates(client, orders)
    fmt.Println("All order updates sent")
}

📧 Email Sending

Send HTML emails with Go's template system:

package main

import (
    "bytes"
    "context"
    "fmt"
    "html/template"
    "sync"
    "time"
)

// Email helper with template support
func sendEmail(client *TeamConnectClient, to, subject, html string, options map[string]interface{}) error {
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    data := map[string]interface{}{
        "to":      to,
        "subject": subject,
        "html":    html,
    }

    for key, value := range options {
        data[key] = value
    }

    resp, err := client.MakeRequest(ctx, "email", "send", data)
    if err != nil {
        return fmt.Errorf("email failed: %w", err)
    }

    if !resp.Success {
        return fmt.Errorf("email failed: %s", resp.Error)
    }

    fmt.Printf("✅ Email sent successfully!\n")
    if messageID, ok := resp.Result["message_id"].(string); ok {
        fmt.Printf("Message ID: %s\n", messageID)
    }

    return nil
}

// Email template system
type EmailTemplate struct {
    tmpl *template.Template
}

func NewEmailTemplate(templateStr string) (*EmailTemplate, error) {
    tmpl, err := template.New("email").Parse(templateStr)
    if err != nil {
        return nil, fmt.Errorf("parse template: %w", err)
    }
    
    return &EmailTemplate{tmpl: tmpl}, nil
}

func (et *EmailTemplate) Render(data interface{}) (string, error) {
    var buf bytes.Buffer
    if err := et.tmpl.Execute(&buf, data); err != nil {
        return "", fmt.Errorf("execute template: %w", err)
    }
    return buf.String(), nil
}

// Welcome email template
const welcomeEmailTemplate = `



    


    

Welcome to {{.CompanyName}}!

Hi {{.CustomerName}},

Thanks for signing up! Your account is now active and ready to use.

Get started by exploring our features:

  • 🎤 AI Voice Calls
  • 💬 SMS Messaging
  • 📧 Email Campaigns
  • 🤖 AI Chat Integration
Get Started

If you have any questions, just reply to this email!

` type WelcomeEmailData struct { CustomerName string CompanyName string DashboardURL string } // Email campaign system type EmailCampaign struct { client *TeamConnectClient template *EmailTemplate semaphore chan struct{} } func NewEmailCampaign(client *TeamConnectClient, templateStr string, concurrency int) (*EmailCampaign, error) { tmpl, err := NewEmailTemplate(templateStr) if err != nil { return nil, err } return &EmailCampaign{ client: client, template: tmpl, semaphore: make(chan struct{}, concurrency), }, nil } type EmailRecipient struct { Email string Data interface{} } func (ec *EmailCampaign) SendBatch(subject string, recipients []EmailRecipient) []error { var wg sync.WaitGroup errors := make([]error, len(recipients)) for i, recipient := range recipients { wg.Add(1) go func(index int, rcpt EmailRecipient) { defer wg.Done() // Rate limiting ec.semaphore <- struct{}{} defer func() { <-ec.semaphore }() // Render template html, err := ec.template.Render(rcpt.Data) if err != nil { errors[index] = fmt.Errorf("render template: %w", err) return } // Send email if err := sendEmail(ec.client, rcpt.Email, subject, html, map[string]interface{}{ "from_name": "Dad-Link Team", }); err != nil { errors[index] = err } }(i, recipient) } wg.Wait() return errors } // Invoice email system const invoiceEmailTemplate = `

Invoice #{{.InvoiceNumber}}

Hi {{.CustomerName}},

Your invoice is ready for payment.

Amount Due: £{{printf "%.2f" .Amount}}

Due Date: {{.DueDate.Format "January 2, 2006"}}

Pay Now
` type InvoiceEmailData struct { CustomerName string InvoiceNumber string Amount float64 DueDate time.Time PaymentURL string } func main() { client := NewTeamConnectClient("tc_live_your_api_key_here") // Welcome email campaign campaign, err := NewEmailCampaign(client, welcomeEmailTemplate, 5) if err != nil { fmt.Printf("Failed to create campaign: %v\n", err) return } recipients := []EmailRecipient{ { Email: "john@example.com", Data: WelcomeEmailData{ CustomerName: "John Doe", CompanyName: "Dad-Link", DashboardURL: "https://team-connect.co.uk/dashboard.html", }, }, { Email: "jane@example.com", Data: WelcomeEmailData{ CustomerName: "Jane Smith", CompanyName: "Dad-Link", DashboardURL: "https://team-connect.co.uk/dashboard.html", }, }, } fmt.Println("Sending welcome email campaign...") errors := campaign.SendBatch("Welcome to Dad-Link - Your Account is Ready!", recipients) successCount := 0 for i, err := range errors { if err == nil { successCount++ fmt.Printf("✅ Email %d sent successfully\n", i+1) } else { fmt.Printf("❌ Email %d failed: %v\n", i+1, err) } } fmt.Printf("Campaign complete: %d/%d successful\n", successCount, len(recipients)) // Single invoice email invoiceTemplate, err := NewEmailTemplate(invoiceEmailTemplate) if err != nil { fmt.Printf("Failed to create invoice template: %v\n", err) return } invoiceData := InvoiceEmailData{ CustomerName: "Alice Johnson", InvoiceNumber: "INV-2025-001", Amount: 125.50, DueDate: time.Now().Add(30 * 24 * time.Hour), PaymentURL: "https://pay.dad-link.com/INV-2025-001", } html, err := invoiceTemplate.Render(invoiceData) if err != nil { fmt.Printf("Failed to render invoice: %v\n", err) return } if err := sendEmail(client, "alice@example.com", "Invoice #INV-2025-001 - Payment Due", html, map[string]interface{}{ "from_name": "Dad-Link Billing", }); err != nil { fmt.Printf("Failed to send invoice: %v\n", err) } }

🤖 AI Chat

Use GPT-4 for intelligent conversations with Go's powerful concurrency:

package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

// AI Chat helper
func chatAI(client *TeamConnectClient, messages []map[string]string, model string) (string, error) {
    ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
    defer cancel()

    if model == "" {
        model = "gpt-4"
    }

    data := map[string]interface{}{
        "messages": messages,
        "model":    model,
    }

    resp, err := client.MakeRequest(ctx, "ai", "chat", data)
    if err != nil {
        return "", fmt.Errorf("AI chat failed: %w", err)
    }

    if !resp.Success {
        return "", fmt.Errorf("AI chat failed: %s", resp.Error)
    }

    if response, ok := resp.Result["response"].(string); ok {
        return response, nil
    }

    return "", fmt.Errorf("invalid response format")
}

// Customer support bot
type CustomerSupportBot struct {
    client        *TeamConnectClient
    conversations sync.Map // thread-safe conversation storage
}

func NewCustomerSupportBot(client *TeamConnectClient) *CustomerSupportBot {
    return &CustomerSupportBot{
        client: client,
    }
}

type Conversation struct {
    Messages []map[string]string
    LastUsed time.Time
}

func (bot *CustomerSupportBot) SendMessage(userID, message string) (string, error) {
    // Load or create conversation
    var conv *Conversation
    if value, exists := bot.conversations.Load(userID); exists {
        conv = value.(*Conversation)
    } else {
        conv = &Conversation{
            Messages: []map[string]string{
                {
                    "role":    "system",
                    "content": "You are a helpful customer support assistant for Dad-Link, a communication platform. Be friendly and provide accurate information about our voice, SMS, email, and AI services.",
                },
            },
        }
    }

    // Add user message
    conv.Messages = append(conv.Messages, map[string]string{
        "role":    "user",
        "content": message,
    })

    // Get AI response
    response, err := chatAI(bot.client, conv.Messages, "gpt-4")
    if err != nil {
        return "", err
    }

    // Add AI response to conversation
    conv.Messages = append(conv.Messages, map[string]string{
        "role":    "assistant",
        "content": response,
    })

    // Update conversation
    conv.LastUsed = time.Now()
    bot.conversations.Store(userID, conv)

    return response, nil
}

func (bot *CustomerSupportBot) ClearOldConversations() {
    cutoff := time.Now().Add(-24 * time.Hour)
    
    bot.conversations.Range(func(key, value interface{}) bool {
        conv := value.(*Conversation)
        if conv.LastUsed.Before(cutoff) {
            bot.conversations.Delete(key)
        }
        return true
    })
}

// Content generation system
type ContentGenerator struct {
    client *TeamConnectClient
}

func NewContentGenerator(client *TeamConnectClient) *ContentGenerator {
    return &ContentGenerator{client: client}
}

func (cg *ContentGenerator) GenerateEmailSubjects(product, audience string, count int) ([]string, error) {
    prompt := fmt.Sprintf(
        "Generate %d compelling email subject lines for %s targeting %s. Make them engaging and click-worthy. Return only the subject lines, one per line.",
        count, product, audience,
    )

    messages := []map[string]string{
        {
            "role":    "system",
            "content": "You are a marketing copywriter specializing in email subject lines.",
        },
        {
            "role":    "user",
            "content": prompt,
        },
    }

    response, err := chatAI(cg.client, messages, "gpt-4")
    if err != nil {
        return nil, err
    }

    // Parse response into lines
    subjects := []string{}
    lines := splitLines(response)
    for _, line := range lines {
        if trimmed := trimString(line); trimmed != "" {
            subjects = append(subjects, trimmed)
        }
    }

    return subjects, nil
}

func (cg *ContentGenerator) GenerateProductDescription(product, features string) (string, error) {
prompt := fmt.Sprintf(
    "Write a compelling product description for %s with these features: %s. Make it professional and persuasive.",
    product, features,
)

messages := []map[string]string{
    {
        "role":    "system",
        "content": "You are a product marketing specialist who writes compelling product descriptions.",
    },
    {
        "role":    "user",
        "content": prompt,
    },
}

return chatAI(cg.client, messages, "gpt-4")
}

// Concurrent AI processing
func (cg *ContentGenerator) GenerateBatchContent(requests []string) []string {
results := make([]string, len(requests))
var wg sync.WaitGroup
semaphore := make(chan struct{}, 3) // Limit concurrent AI requests

for i, request := range requests {
    wg.Add(1)
    go func(index int, prompt string) {
        defer wg.Done()
        
        semaphore <- struct{}{}
        defer func() { <-semaphore }()

        messages := []map[string]string{
            {
                "role":    "system",
                "content": "You are a helpful AI assistant.",
            },
            {
                "role":    "user",
                "content": prompt,
            },
        }

        response, err := chatAI(cg.client, messages, "gpt-4")
        if err != nil {
            results[index] = fmt.Sprintf("Error: %v", err)
        } else {
            results[index] = response
        }
    }(i, request)
}

wg.Wait()
return results
}

// Helper functions
func splitLines(text string) []string {
// Simple line splitting - in production, use strings.Split
lines := []string{}
current := ""
for _, char := range text {
    if char == '\n' {
        lines = append(lines, current)
        current = ""
    } else {
        current += string(char)
    }
}
if current != "" {
    lines = append(lines, current)
}
return lines
}

func trimString(s string) string {
// Simple trim - in production, use strings.TrimSpace
for len(s) > 0 && (s[0] == ' ' || s[0] == '\t' || s[0] == '\n' || s[0] == '\r') {
    s = s[1:]
}
for len(s) > 0 && (s[len(s)-1] == ' ' || s[len(s)-1] == '\t' || s[len(s)-1] == '\n' || s[len(s)-1] == '\r') {
    s = s[:len(s)-1]
}
return s
}

func main() {
client := NewTeamConnectClient("tc_live_your_api_key_here")

// Customer support bot example
bot := NewCustomerSupportBot(client)

// Simulate customer conversation
response1, err := bot.SendMessage("user123", "Hello, how can I integrate voice calls into my Go application?")
if err != nil {
    fmt.Printf("Bot error: %v\n", err)
    return
}
fmt.Printf("Bot: %s\n\n", response1)

response2, err := bot.SendMessage("user123", "What's the pricing for voice calls?")
if err != nil {
    fmt.Printf("Bot error: %v\n", err)
    return
}
fmt.Printf("Bot: %s\n\n", response2)

// Content generation example
generator := NewContentGenerator(client)

subjects, err := generator.GenerateEmailSubjects("Team Connect API", "software developers", 5)
if err != nil {
    fmt.Printf("Content generation error: %v\n", err)
    return
}

fmt.Println("Generated email subjects:")
for i, subject := range subjects {
    fmt.Printf("%d. %s\n", i+1, subject)
}

// Batch content generation
prompts := []string{
    "Write a tagline for a communication API",
    "Create a tweet about voice AI technology",
    "Generate a LinkedIn post about developer tools",
}

fmt.Println("\nBatch content generation:")
results := generator.GenerateBatchContent(prompts)
for i, result := range results {
    fmt.Printf("Prompt %d result: %s\n\n", i+1, result)
}

// Clean up old conversations
bot.ClearOldConversations()
}

⚡ Framework Examples

Ready-to-use examples for popular Go frameworks and architectures:

// Gin Web Framework Integration
package main

import (
"net/http"
"os"

"github.com/gin-gonic/gin"
)

type CommunicationService struct {
teamConnect *TeamConnectClient
}

func NewCommunicationService(apiKey string) *CommunicationService {
return &CommunicationService{
    teamConnect: NewTeamConnectClient(apiKey),
}
}

// Request/Response structs
type CallRequest struct {
To      string `json:"to" binding:"required"`
Message string `json:"message" binding:"required"`
Voice   string `json:"voice,omitempty"`
}

type SMSRequest struct {
To      string `json:"to" binding:"required"`
Message string `json:"message" binding:"required"`
}

type EmailRequest struct {
To       string `json:"to" binding:"required"`
Subject  string `json:"subject" binding:"required"`
HTML     string `json:"html" binding:"required"`
FromName string `json:"from_name,omitempty"`
}

type APIResponse struct {
Success bool        `json:"success"`
Data    interface{} `json:"data,omitempty"`
Error   string      `json:"error,omitempty"`
}

// Gin handlers
func (cs *CommunicationService) MakeCall(c *gin.Context) {
var req CallRequest
if err := c.ShouldBindJSON(&req); err != nil {
    c.JSON(http.StatusBadRequest, APIResponse{
        Success: false,
        Error:   err.Error(),
    })
    return
}

options := map[string]interface{}{}
if req.Voice != "" {
    options["voice"] = req.Voice
}

resp, err := cs.teamConnect.MakeRequest(c.Request.Context(), "voice", "make_call", map[string]interface{}{
    "to":      req.To,
    "message": req.Message,
    "voice":   req.Voice,
})

if err != nil {
    c.JSON(http.StatusInternalServerError, APIResponse{
        Success: false,
        Error:   err.Error(),
    })
    return
}

c.JSON(http.StatusOK, APIResponse{
    Success: true,
    Data:    resp.Result,
})
}

func (cs *CommunicationService) SendSMS(c *gin.Context) {
var req SMSRequest
if err := c.ShouldBindJSON(&req); err != nil {
    c.JSON(http.StatusBadRequest, APIResponse{
        Success: false,
        Error:   err.Error(),
    })
    return
}

resp, err := cs.teamConnect.MakeRequest(c.Request.Context(), "sms", "send", map[string]interface{}{
    "to":      req.To,
    "message": req.Message,
})

if err != nil {
    c.JSON(http.StatusInternalServerError, APIResponse{
        Success: false,
        Error:   err.Error(),
    })
    return
}

c.JSON(http.StatusOK, APIResponse{
    Success: true,
    Data:    resp.Result,
})
}

func (cs *CommunicationService) SendEmail(c *gin.Context) {
var req EmailRequest
if err := c.ShouldBindJSON(&req); err != nil {
    c.JSON(http.StatusBadRequest, APIResponse{
        Success: false,
        Error:   err.Error(),
    })
    return
}

data := map[string]interface{}{
    "to":      req.To,
    "subject": req.Subject,
    "html":    req.HTML,
}
if req.FromName != "" {
    data["from_name"] = req.FromName
}

resp, err := cs.teamConnect.MakeRequest(c.Request.Context(), "email", "send", data)

if err != nil {
    c.JSON(http.StatusInternalServerError, APIResponse{
        Success: false,
        Error:   err.Error(),
    })
    return
}

c.JSON(http.StatusOK, APIResponse{
    Success: true,
    Data:    resp.Result,
})
}

// Webhook handler
func (cs *CommunicationService) HandleWebhook(c *gin.Context) {
var payload map[string]interface{}
if err := c.ShouldBindJSON(&payload); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
}

event, _ := payload["event"].(string)
data, _ := payload["data"].(map[string]interface{})

// Process webhook based on event type
switch event {
case "call.completed":
    callID, _ := data["call_id"].(string)
    fmt.Printf("Call completed: %s\n", callID)
    // Update database, send notifications, etc.
case "sms.delivered":
    messageID, _ := data["message_id"].(string)
    fmt.Printf("SMS delivered: %s\n", messageID)
case "email.delivered":
    messageID, _ := data["message_id"].(string)
    fmt.Printf("Email delivered: %s\n", messageID)
}

c.JSON(http.StatusOK, gin.H{"received": true})
}

func main() {
// Initialize service
apiKey := os.Getenv("TEAM_CONNECT_API_KEY")
if apiKey == "" {
    panic("TEAM_CONNECT_API_KEY environment variable required")
}

service := NewCommunicationService(apiKey)

// Setup Gin router
r := gin.Default()

// API routes
api := r.Group("/api/v1")
{
    api.POST("/call", service.MakeCall)
    api.POST("/sms", service.SendSMS)
    api.POST("/email", service.SendEmail)
    api.POST("/webhooks/team-connect", service.HandleWebhook)
}

// Health check
r.GET("/health", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"status": "healthy"})
})

// Start server
r.Run(":8080")
}
// Fiber Framework Integration
package main

import (
"log"
"os"

"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
)

type FiberCommunicationHandler struct {
teamConnect *TeamConnectClient
}

func NewFiberCommunicationHandler(apiKey string) *FiberCommunicationHandler {
return &FiberCommunicationHandler{
    teamConnect: NewTeamConnectClient(apiKey),
}
}

func (h *FiberCommunicationHandler) MakeCall(c *fiber.Ctx) error {
var req CallRequest
if err := c.BodyParser(&req); err != nil {
    return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
        "success": false,
        "error":   err.Error(),
    })
}

resp, err := h.teamConnect.MakeRequest(c.Context(), "voice", "make_call", map[string]interface{}{
    "to":      req.To,
    "message": req.Message,
    "voice":   req.Voice,
})

if err != nil {
    return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
        "success": false,
        "error":   err.Error(),
    })
}

return c.JSON(fiber.Map{
    "success": true,
    "data":    resp.Result,
})
}

func (h *FiberCommunicationHandler) SendSMS(c *fiber.Ctx) error {
var req SMSRequest
if err := c.BodyParser(&req); err != nil {
    return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
        "success": false,
        "error":   err.Error(),
    })
}

resp, err := h.teamConnect.MakeRequest(c.Context(), "sms", "send", map[string]interface{}{
    "to":      req.To,
    "message": req.Message,
})

if err != nil {
    return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
        "success": false,
        "error":   err.Error(),
    })
}

return c.JSON(fiber.Map{
    "success": true,
    "data":    resp.Result,
})
}

func main() {
apiKey := os.Getenv("TEAM_CONNECT_API_KEY")
if apiKey == "" {
    log.Fatal("TEAM_CONNECT_API_KEY environment variable required")
}

handler := NewFiberCommunicationHandler(apiKey)

app := fiber.New(fiber.Config{
    AppName: "Team Connect API Server",
})

// Middleware
app.Use(logger.New())
app.Use(recover.New())
app.Use(cors.New())

// API routes
api := app.Group("/api/v1")
api.Post("/call", handler.MakeCall)
api.Post("/sms", handler.SendSMS)

// Health check
app.Get("/health", func(c *fiber.Ctx) error {
    return c.JSON(fiber.Map{"status": "healthy"})
})

log.Fatal(app.Listen(":3000"))
}
// Microservice Architecture
package main

import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"sync"
"syscall"
"time"
)

// Communication microservice
type CommunicationMicroservice struct {
teamConnect *TeamConnectClient
server      *http.Server
wg          sync.WaitGroup
}

func NewCommunicationMicroservice(apiKey string, port string) *CommunicationMicroservice {
mux := http.NewServeMux()

service := &CommunicationMicroservice{
    teamConnect: NewTeamConnectClient(apiKey),
    server: &http.Server{
        Addr:         ":" + port,
        Handler:      mux,
        ReadTimeout:  30 * time.Second,
        WriteTimeout: 30 * time.Second,
        IdleTimeout:  120 * time.Second,
    },
}

// Register routes
mux.HandleFunc("/health", service.healthHandler)
mux.HandleFunc("/metrics", service.metricsHandler)
mux.HandleFunc("/api/v1/call", service.callHandler)
mux.HandleFunc("/api/v1/sms", service.smsHandler)
mux.HandleFunc("/api/v1/email", service.emailHandler)
mux.HandleFunc("/webhooks/team-connect", service.webhookHandler)

return service
}

func (ms *CommunicationMicroservice) healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
    "status":    "healthy",
    "timestamp": time.Now().UTC(),
    "service":   "communication-api",
})
}

func (ms *CommunicationMicroservice) metricsHandler(w http.ResponseWriter, r *http.Request) {
// In production, integrate with Prometheus
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintf(w, "# HELP team_connect_requests_total Total requests\n")
fmt.Fprintf(w, "# TYPE team_connect_requests_total counter\n")
fmt.Fprintf(w, "team_connect_requests_total 42\n")
}

func (ms *CommunicationMicroservice) callHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
    http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
    return
}

var req CallRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
}

resp, err := ms.teamConnect.MakeRequest(r.Context(), "voice", "make_call", map[string]interface{}{
    "to":      req.To,
    "message": req.Message,
    "voice":   req.Voice,
})

w.Header().Set("Content-Type", "application/json")

if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    json.NewEncoder(w).Encode(map[string]interface{}{
        "success": false,
        "error":   err.Error(),
    })
    return
}

json.NewEncoder(w).Encode(map[string]interface{}{
    "success": true,
    "data":    resp.Result,
})
}

func (ms *CommunicationMicroservice) smsHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
    http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
    return
}

var req SMSRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
}

resp, err := ms.teamConnect.MakeRequest(r.Context(), "sms", "send", map[string]interface{}{
    "to":      req.To,
    "message": req.Message,
})

w.Header().Set("Content-Type", "application/json")

if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    json.NewEncoder(w).Encode(map[string]interface{}{
        "success": false,
        "error":   err.Error(),
    })
    return
}

json.NewEncoder(w).Encode(map[string]interface{}{
    "success": true,
    "data":    resp.Result,
})
}

func (ms *CommunicationMicroservice) emailHandler(w http.ResponseWriter, r *http.Request) {
// Similar implementation to SMS
}

func (ms *CommunicationMicroservice) webhookHandler(w http.ResponseWriter, r *http.Request) {
var payload map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
}

// Process webhook asynchronously
ms.wg.Add(1)
go func() {
    defer ms.wg.Done()
    ms.processWebhook(payload)
}()

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]bool{"received": true})
}

func (ms *CommunicationMicroservice) processWebhook(payload map[string]interface{}) {
event, _ := payload["event"].(string)
data, _ := payload["data"].(map[string]interface{})

log.Printf("Processing webhook: %s", event)

switch event {
case "call.completed":
    // Update database, send notifications
case "sms.delivered":
    // Track delivery metrics
case "email.delivered":
    // Update campaign stats
}
}

func (ms *CommunicationMicroservice) Start() error {
log.Printf("Starting communication microservice on %s", ms.server.Addr)
return ms.server.ListenAndServe()
}

func (ms *CommunicationMicroservice) Stop(ctx context.Context) error {
log.Println("Shutting down communication microservice...")

// Stop HTTP server
if err := ms.server.Shutdown(ctx); err != nil {
    return err
}

// Wait for goroutines to finish
done := make(chan struct{})
go func() {
    ms.wg.Wait()
    close(done)
}()

select {
case <-done:
    log.Println("All goroutines finished")
case <-ctx.Done():
    log.Println("Timeout waiting for goroutines")
    return ctx.Err()
}

return nil
}

func main() {
apiKey := os.Getenv("TEAM_CONNECT_API_KEY")
if apiKey == "" {
    log.Fatal("TEAM_CONNECT_API_KEY environment variable required")
}

port := os.Getenv("PORT")
if port == "" {
    port = "8080"
}

service := NewCommunicationMicroservice(apiKey, port)

// Handle graceful shutdown
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

go func() {
    if err := service.Start(); err != nil && err != http.ErrServerClosed {
        log.Fatalf("Server failed to start: %v", err)
    }
}()

<-quit
log.Println("Received shutdown signal")

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if err := service.Stop(ctx); err != nil {
    log.Fatalf("Server failed to shutdown: %v", err)
}

log.Println("Server stopped gracefully")
}
// gRPC Service Implementation
// communication.proto
/*
syntax = "proto3";

package communication;

option go_package = "github.com/your-org/communication/pb";

service CommunicationService {
rpc MakeCall(CallRequest) returns (CallResponse);
rpc SendSMS(SMSRequest) returns (SMSResponse);
rpc SendEmail(EmailRequest) returns (EmailResponse);
rpc ChatAI(ChatRequest) returns (ChatResponse);
}

message CallRequest {
string to = 1;
string message = 2;
string voice = 3;
string webhook_url = 4;
}

message CallResponse {
bool success = 1;
string call_id = 2;
string status = 3;
string error = 4;
BillingInfo billing = 5;
}

message SMSRequest {
string to = 1;
string message = 2;
string from = 3;
}

message SMSResponse {
bool success = 1;
string message_id = 2;
string status = 3;
string error = 4;
BillingInfo billing = 5;
}

message EmailRequest {
string to = 1;
string subject = 2;
string html = 3;
string from_name = 4;
}

message EmailResponse {
bool success = 1;
string message_id = 2;
string status = 3;
string error = 4;
BillingInfo billing = 5;
}

message ChatRequest {
repeated ChatMessage messages = 1;
string model = 2;
}

message ChatMessage {
string role = 1;
string content = 2;
}

message ChatResponse {
bool success = 1;
string response = 2;
string model = 3;
int32 tokens_used = 4;
string error = 5;
BillingInfo billing = 6;
}

message BillingInfo {
double cost = 1;
string cost_formatted = 2;
string service = 3;
string action = 4;
double credits_remaining = 5;
string credits_remaining_formatted = 6;
}
*/

// Generated Go code would be imported here
// import pb "github.com/your-org/communication/pb"

package main

import (
"context"
"fmt"
"log"
"net"

"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

// gRPC server implementation
type CommunicationServer struct {
// pb.UnimplementedCommunicationServiceServer
teamConnect *TeamConnectClient
}

func NewCommunicationServer(apiKey string) *CommunicationServer {
return &CommunicationServer{
    teamConnect: NewTeamConnectClient(apiKey),
}
}

// Simulated protobuf message types (replace with actual generated code)
type CallRequest struct {
To         string
Message    string
Voice      string
WebhookUrl string
}

type CallResponse struct {
Success bool
CallId  string
Status  string
Error   string
Billing *BillingInfo
}

type BillingInfo struct {
Cost                      float64
CostFormatted            string
Service                  string
Action                   string
CreditsRemaining         float64
CreditsRemainingFormatted string
}

func (s *CommunicationServer) MakeCall(ctx context.Context, req *CallRequest) (*CallResponse, error) {
if req.To == "" || req.Message == "" {
    return nil, status.Errorf(codes.InvalidArgument, "to and message are required")
}

data := map[string]interface{}{
    "to":      req.To,
    "message": req.Message,
}

if req.Voice != "" {
    data["voice"] = req.Voice
}
if req.WebhookUrl != "" {
    data["webhook_url"] = req.WebhookUrl
}

resp, err := s.teamConnect.MakeRequest(ctx, "voice", "make_call", data)
if err != nil {
    return &CallResponse{
        Success: false,
        Error:   err.Error(),
    }, nil
}

callResponse := &CallResponse{
    Success: resp.Success,
}

if resp.Success {
    if callID, ok := resp.Result["call_id"].(string); ok {
        callResponse.CallId = callID
    }
    if status, ok := resp.Result["status"].(string); ok {
        callResponse.Status = status
    }
    
    if resp.Billing != nil {
        callResponse.Billing = &BillingInfo{}
        if cost, ok := resp.Billing["cost"].(float64); ok {
            callResponse.Billing.Cost = cost
        }
        if costFormatted, ok := resp.Billing["costFormatted"].(string); ok {
            callResponse.Billing.CostFormatted = costFormatted
        }
    }
} else {
    callResponse.Error = resp.Error
}

return callResponse, nil
}

// gRPC client example
type CommunicationClient struct {
conn   *grpc.ClientConn
client pb.CommunicationServiceClient
}

func NewCommunicationClient(serverAddr string) (*CommunicationClient, error) {
conn, err := grpc.Dial(serverAddr, grpc.WithInsecure())
if err != nil {
    return nil, err
}

return &CommunicationClient{
    conn:   conn,
    client: pb.NewCommunicationServiceClient(conn),
}, nil
}

func (c *CommunicationClient) Close() error {
return c.conn.Close()
}

func (c *CommunicationClient) MakeCall(ctx context.Context, to, message, voice string) (*CallResponse, error) {
req := &CallRequest{
    To:      to,
    Message: message,
    Voice:   voice,
}

return c.client.MakeCall(ctx, req)
}

func main() {
// Server mode
if len(os.Args) > 1 && os.Args[1] == "server" {
    apiKey := os.Getenv("TEAM_CONNECT_API_KEY")
    if apiKey == "" {
        log.Fatal("TEAM_CONNECT_API_KEY environment variable required")
    }

    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
    }

    s := grpc.NewServer()
    communicationServer := NewCommunicationServer(apiKey)
    
    // pb.RegisterCommunicationServiceServer(s, communicationServer)

    log.Println("gRPC server listening on :50051")
    if err := s.Serve(lis); err != nil {
        log.Fatalf("Failed to serve: %v", err)
    }
} else {
    // Client mode
    client, err := NewCommunicationClient("localhost:50051")
    if err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer client.Close()

    ctx := context.Background()
    resp, err := client.MakeCall(ctx, "+447123456789", "Hello from gRPC!", "Polly.Amy")
    if err != nil {
        log.Fatalf("Call failed: %v", err)
    }

    if resp.Success {
        fmt.Printf("✅ Call successful: %s\n", resp.CallId)
    } else {
        fmt.Printf("❌ Call failed: %s\n", resp.Error)
    }
}
}

⚠️ Error Handling

Production-ready error handling with Go's robust error patterns:

// Custom error types
type TeamConnectError struct {
Code    string
Message string
Cause   error
}

func (e *TeamConnectError) Error() string {
if e.Cause != nil {
    return fmt.Sprintf("%s: %s (caused by: %v)", e.Code, e.Message, e.Cause)
}
return fmt.Sprintf("%s: %s", e.Code, e.Message)
}

func (e *TeamConnectError) Unwrap() error {
return e.Cause
}

// Specific error types
var (
ErrInvalidAPIKey       = &TeamConnectError{Code: "INVALID_API_KEY", Message: "Invalid or revoked API key"}
ErrInsufficientCredits = &TeamConnectError{Code: "INSUFFICIENT_CREDITS", Message: "Insufficient credits"}
ErrRateLimitExceeded   = &TeamConnectError{Code: "RATE_LIMIT_EXCEEDED", Message: "Rate limit exceeded"}
ErrServiceUnavailable  = &TeamConnectError{Code: "SERVICE_UNAVAILABLE", Message: "Service temporarily unavailable"}
)

// Enhanced client with circuit breaker
type EnhancedTeamConnectClient struct {
*TeamConnectClient
circuitBreaker *CircuitBreaker
metrics        *Metrics
}

type CircuitBreaker struct {
maxFailures    int
resetTimeout   time.Duration
failureCount   int
lastFailure    time.Time
state          string // "CLOSED", "OPEN", "HALF_OPEN"
mutex          sync.RWMutex
}

func NewCircuitBreaker(maxFailures int, resetTimeout time.Duration) *CircuitBreaker {
return &CircuitBreaker{
    maxFailures:  maxFailures,
    resetTimeout: resetTimeout,
    state:        "CLOSED",
}
}

func (cb *CircuitBreaker) Call(fn func() error) error {
cb.mutex.RLock()
state := cb.state
failureCount := cb.failureCount
lastFailure := cb.lastFailure
cb.mutex.RUnlock()

if state == "OPEN" {
    if time.Since(lastFailure) > cb.resetTimeout {
        cb.mutex.Lock()
        cb.state = "HALF_OPEN"
        cb.mutex.Unlock()
    } else {
        return &TeamConnectError{
            Code:    "CIRCUIT_BREAKER_OPEN",
            Message: "Circuit breaker is open",
        }
    }
}

err := fn()

cb.mutex.Lock()
defer cb.mutex.Unlock()

if err != nil {
    cb.failureCount++
    cb.lastFailure = time.Now()

    if cb.failureCount >= cb.maxFailures {
        cb.state = "OPEN"
    }

    return err
}

// Success - reset circuit breaker
cb.failureCount = 0
cb.state = "CLOSED"
return nil
}

type Metrics struct {
RequestCount    int64
SuccessCount    int64
ErrorCount      int64
LastRequestTime time.Time
mutex           sync.RWMutex
}

func (m *Metrics) RecordRequest(success bool) {
m.mutex.Lock()
defer m.mutex.Unlock()

m.RequestCount++
m.LastRequestTime = time.Now()

if success {
    m.SuccessCount++
} else {
    m.ErrorCount++
}
}

func (m *Metrics) GetStats() (int64, int64, int64, time.Time) {
m.mutex.RLock()
defer m.mutex.RUnlock()
return m.RequestCount, m.SuccessCount, m.ErrorCount, m.LastRequestTime
}

func NewEnhancedTeamConnectClient(apiKey string) *EnhancedTeamConnectClient {
return &EnhancedTeamConnectClient{
    TeamConnectClient: NewTeamConnectClient(apiKey),
    circuitBreaker:    NewCircuitBreaker(5, 60*time.Second),
    metrics:          &Metrics{},
}
}

func (c *EnhancedTeamConnectClient) MakeRequestSafe(ctx context.Context, service, action string, data interface{}) (*APIResponse, error) {
var result *APIResponse
var err error

circuitErr := c.circuitBreaker.Call(func() error {
    result, err = c.MakeRequest(ctx, service, action, data)
    return err
})

success := err == nil && circuitErr == nil
c.metrics.RecordRequest(success)

if circuitErr != nil {
    return nil, circuitErr
}

return result, err
}

// Retry wrapper with exponential backoff
func (c *EnhancedTeamConnectClient) MakeRequestWithRetry(ctx context.Context, service, action string, data interface{}, maxRetries int) (*APIResponse, error) {
var lastErr error

for attempt := 0; attempt <= maxRetries; attempt++ {
    resp, err := c.MakeRequestSafe(ctx, service, action, data)
    if err == nil {
        return resp, nil
    }

    lastErr = err

    // Check if error is retryable
    var teamConnectErr *TeamConnectError
    if errors.As(err, &teamConnectErr) {
        switch teamConnectErr.Code {
        case "INVALID_API_KEY", "INSUFFICIENT_CREDITS":
            // Don't retry these errors
            return nil, err
        }
    }

    // Check context cancellation
    if ctx.Err() != nil {
        return nil, ctx.Err()
    }

    // Don't wait after last attempt
    if attempt == maxRetries {
        break
    }

    // Exponential backoff with jitter
    backoff := time.Duration(1<

💰 Pricing

Enterprise-grade pricing perfect for Go microservices and cloud applications:

Service Price Unit Go Example
📞 Voice Calls 7p per minute client.MakeRequest(ctx, "voice", "make_call", data)
💬 SMS Messages 3p per message client.MakeRequest(ctx, "sms", "send", data)
📧 Email Sending 0.15p per email client.MakeRequest(ctx, "email", "send", data)
🤖 AI Processing 15p per request client.MakeRequest(ctx, "ai", "chat", data)

💡 Go Microservices Cost Example

Cloud-native microservices with 100,000 users:

  • 10,000 voice calls (2 min avg) = £1,400.00
  • 50,000 SMS messages = £1,500.00
  • 200,000 emails = £300.00
  • 5,000 AI requests = £750.00
  • Total: £3,950.00/month (vs £500k+ building in-house)
🐹 Perfect for Go: Our API is built for high-performance, concurrent applications. Zero external dependencies, context support, graceful shutdowns, and production-ready error handling make it ideal for cloud-native Go services.

💳 Manage Credits: Visit your API Dashboard to top up credits and monitor usage across your microservices.

Need help? Contact us at support@team-connect.co.uk

← Back to API Dashboard | REST API Docs | gRPC Examples

© 2025 Dad-Link. All rights reserved. | Last updated: 2025-08-05 15:24:59 UTC