SDK
v0.1.0
Go SDK
The official Go SDK for Sendexa. One module, one client, every API — SMS, OTP, WhatsApp, Email, Voice, and Webhook verification.
Zero Dependencies
Standard library only — net/http, crypto/hmac, encoding/json. No go.sum bloat.
Context-First
Every method accepts a context.Context for cancellation, deadlines, and tracing.
Idiomatic Go
Functional options, exported struct types, error returns — no surprises.
Go 1.21+
Uses standard generics-free patterns. Concurrency-safe for goroutine use.
Installation
Bash
go get github.com/sendexa/sendexa-go
Requirements
Go 1.21 or later. Zero external dependencies — the SDK uses only the Go standard library.
Initialise the Client
Create one client at startup and reuse it — the client is goroutine-safe and manages its own connection pool.
Go
import ("log""os"sendexa "github.com/sendexa/sendexa-go")client, err := sendexa.New(sendexa.WithAPIKey(os.Getenv("SENDEXA_API_KEY"),os.Getenv("SENDEXA_API_SECRET"),),)if err != nil {log.Fatal(err)}
API Examples
Send single and bulk SMS messages with delivery tracking.
Go
// Send a single SMSresp, err := client.SMS.Send(ctx, &sendexa.SendSMSRequest{To: "0244123456",From: "MyBrand",Message: "Your order #1234 has been confirmed!",})if err != nil {log.Fatal(err)}fmt.Println(resp.Data.MessageID, resp.Data.Status)// Send bulk SMSclient.SMS.SendBulk(ctx, &sendexa.SendBulkSMSRequest{From: "MyBrand",Message: "Hello from MyBrand!",Messages: []sendexa.BulkSMSMessage{{To: "0244123456", Message: "Hi Alice!"},{To: "0555987654"}, // uses shared message},})// Check delivery statusstatus, _ := client.SMS.GetStatus(ctx, resp.Data.MessageID)fmt.Println(status.Data.Status) // "delivered"// Resend a failed messageclient.SMS.Resend(ctx, resp.Data.MessageID)
Error Handling
All API errors return a *SendexaError which implements the error interface with structured fields for easy branching.
Go
import sendexa "github.com/sendexa/sendexa-go"_, err := client.SMS.Send(ctx, &sendexa.SendSMSRequest{To: "0244123456", From: "MyBrand", Message: "Hi!",})if err != nil {var apiErr *sendexa.SendexaErrorif errors.As(err, &apiErr) {fmt.Println(apiErr.Status) // HTTP status e.g. 403fmt.Println(apiErr.Code) // API code e.g. "SENDER_ID_NOT_APPROVED"fmt.Println(apiErr.Message) // Human text e.g. "Sender ID not approved"fmt.Println(apiErr.RequestID) // Trace ID for Sendexa support}}
| Field | Type | Description |
|---|---|---|
| Status | int | HTTP status code (400, 401, 403, 429…) |
| Code | string | Machine-readable error code from the API |
| Message | string | Human-readable description of the error |
| RequestID | string | Sendexa trace ID — include when contacting support |
| Raw | map[string]any | The full raw error payload from the API |
Best Practices
- Create one
*Clientat startup and reuse it — it manages its own HTTP connection pool - Always pass a
context.Contextwith a deadline or timeout to every method call - Store credentials in environment variables, never in source code
- Use
errors.As(err, &apiErr)to branch on*SendexaErrorfields - Call
client.Webhooks.Verify()before processing any webhook event