SDKs
Go SDK
Official Whatify SDK for Go applications
The official Whatify SDK for Go applications with idiomatic Go patterns and full type safety.
Before using this SDK, sign up at https://whatify.dev to get your API token.
Installation
go get github.com/yourorg/whatify-goQuick Start
package main
import (
"fmt"
"log"
"github.com/yourorg/whatify-go"
)
func main() {
client := whatify.NewClient("your-api-token", nil)
// Send a message
resp, err := client.SendText("1234567890", "Hello from Go!")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Message sent: %v\n", resp.Success)
}Configuration
Basic Configuration
import "github.com/yourorg/whatify-go"
client := whatify.NewClient("your-api-token", nil)Custom Configuration
config := &whatify.Config{
APIToken: "your-api-token",
}
client := whatify.NewClient("", config)Using API Key
config := &whatify.Config{
APIKey: "your-api-key",
}
client := whatify.NewClient("", config)From Environment Variables
import "os"
client := whatify.NewClient(os.Getenv("WHATIFY_API_TOKEN"), nil)API Methods
Connect Device
Connect your WhatsApp device.
resp, err := client.Connect()
if err != nil {
log.Fatal(err)
}
fmt.Printf("QR Code: %s\n", resp.QRCode)
fmt.Printf("Status: %s\n", resp.Status)Response:
type ConnectResponse struct {
Success bool `json:"success"`
QRCode string `json:"qrCode,omitempty"`
Status string `json:"status"`
Message string `json:"message"`
}Disconnect Device
resp, err := client.Disconnect()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Disconnected: %v\n", resp.Success)Check Status
resp, err := client.Status()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %s\n", resp.Status)
fmt.Printf("Connected: %v\n", resp.IsConnected)Response:
type StatusResponse struct {
Success bool `json:"success"`
Status string `json:"status"`
IsConnected bool `json:"isConnected"`
Message string `json:"message"`
}Send Messages
Send Text Message
// Single recipient
resp, err := client.SendText("1234567890", "Hello World!")
if err != nil {
log.Fatal(err)
}
// Multiple recipients
resp, err := client.SendText(
[]string{"1234567890", "0987654321"},
"Bulk message",
)
if err != nil {
log.Fatal(err)
}Send Attachment
resp, err := client.SendAttachment("1234567890", &whatify.Attachment{
Type: "image",
URL: "https://example.com/image.jpg",
Caption: "Check this out!",
})
if err != nil {
log.Fatal(err)
}Send Text with Attachment
req := &whatify.SendMessageRequest{
To: "1234567890",
Text: "Here is your document",
Attachment: &whatify.Attachment{
Type: "document",
URL: "https://example.com/report.pdf",
Filename: "report.pdf",
},
}
resp, err := client.Send(req)
if err != nil {
log.Fatal(err)
}Attachment Types:
const (
AttachmentTypeImage = "image"
AttachmentTypeVideo = "video"
AttachmentTypeAudio = "audio"
AttachmentTypeDocument = "document"
)Response:
type SendMessageResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
MessageIDs []string `json:"messageIds,omitempty"`
}Send OTP
Send One-Time Password (OTP) codes via WhatsApp with multi-language support.
Send OTP (English)
resp, err := client.SendOTP("1234567890", "123456", "English")
if err != nil {
log.Fatal(err)
}
fmt.Printf("OTP sent: %+v\n", resp.Data)Send OTP (Arabic)
resp, err := client.SendOTP("1234567890", "654321", "Arabic")
if err != nil {
log.Fatal(err)
}Generate and Send OTP
import (
"math/rand"
"time"
)
// Generate a random 6-digit OTP
rand.Seed(time.Now().UnixNano())
otpCode := fmt.Sprintf("%06d", rand.Intn(1000000))
resp, err := client.SendOTP("1234567890", otpCode, "English")
if err != nil {
log.Fatal(err)
}
// Store OTP in database for verification
otp := &OTP{
Phone: "1234567890",
Code: otpCode,
ExpiresAt: time.Now().Add(10 * time.Minute),
}
db.Create(otp)Using Request Struct
req := &whatify.SendOTPRequest{
Phone: "1234567890",
Code: "123456",
Language: "English",
}
resp, err := client.SendOTPWithRequest(req)
if err != nil {
log.Fatal(err)
}OTP Parameters:
phone(string, required) - Recipient phone number with country codecode(string, required) - OTP code (4-8 digits)language(string, optional) - Message language: "English" or "Arabic" (default: "English")
Response:
type SendOTPResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
Data *SendOTPData `json:"data,omitempty"`
}
type SendOTPData struct {
MessageID string `json:"messageId"`
WhatsAppMessageID string `json:"whatsappMessageId"`
Phone string `json:"phone"`
Code string `json:"code"`
Language string `json:"language"`
SentAt string `json:"sentAt"`
}Expamle OTP Message:
- English:
123456 is your verification code. For your security, do not share this code - Arabic:
123456 هذا هو رمز التحقق الخاص بك. لحمايتك، يرجى عدم مشاركة هذا الرمز.
Error Handling
Type Assertions
resp, err := client.SendText("1234567890", "Hello!")
if err != nil {
if apiErr, ok := err.(*whatify.APIError); ok {
fmt.Printf("API Error: %s (status: %d)\n",
apiErr.Message, apiErr.StatusCode)
} else {
fmt.Printf("Error: %v\n", err)
}
return
}
if resp.Success {
fmt.Println("Message sent successfully!")
}Custom Error Type
type APIError struct {
StatusCode int
Message string
}
func (e *APIError) Error() string {
return fmt.Sprintf("API error %d: %s", e.StatusCode, e.Message)
}Context Support
All methods support context for timeout and cancellation:
import (
"context"
"time"
)
// With timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
resp, err := client.SendTextWithContext(ctx, "1234567890", "Hello!")
if err != nil {
log.Fatal(err)
}// With cancellation
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Cancel after 5 seconds
go func() {
time.Sleep(5 * time.Second)
cancel()
}()
resp, err := client.ConnectWithContext(ctx)
if err != nil {
if err == context.Canceled {
log.Println("Operation canceled")
}
return
}Framework Integration
Gin Web Framework
package main
import (
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/yourorg/whatify-go"
)
var client *whatify.Client
func init() {
client = whatify.NewClient(os.Getenv("WHATIFY_API_TOKEN"), nil)
}
func main() {
r := gin.Default()
r.POST("/send-message", sendMessage)
r.GET("/status", checkStatus)
r.Run(":8080")
}
type SendMessageBody struct {
Phone string `json:"phone" binding:"required"`
Message string `json:"message" binding:"required"`
}
func sendMessage(c *gin.Context) {
var body SendMessageBody
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
resp, err := client.SendText(body.Phone, body.Message)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, resp)
}
func checkStatus(c *gin.Context) {
resp, err := client.Status()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, resp)
}Echo Framework
package main
import (
"net/http"
"os"
"github.com/labstack/echo/v4"
"github.com/yourorg/whatify-go"
)
var client *whatify.Client
func init() {
client = whatify.NewClient(os.Getenv("WHATIFY_API_TOKEN"), nil)
}
func main() {
e := echo.New()
e.POST("/send-message", sendMessage)
e.GET("/status", checkStatus)
e.Start(":8080")
}
type SendMessageRequest struct {
Phone string `json:"phone"`
Message string `json:"message"`
}
func sendMessage(c echo.Context) error {
req := new(SendMessageRequest)
if err := c.Bind(req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{
"error": err.Error(),
})
}
resp, err := client.SendText(req.Phone, req.Message)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": err.Error(),
})
}
return c.JSON(http.StatusOK, resp)
}
func checkStatus(c echo.Context) error {
resp, err := client.Status()
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": err.Error(),
})
}
return c.JSON(http.StatusOK, resp)
}Standard net/http
package main
import (
"encoding/json"
"log"
"net/http"
"os"
"github.com/dilshad4/whatify-go"
)
var client *whatify.Client
func init() {
client = whatify.NewClient(os.Getenv("WHATIFY_API_TOKEN"), nil)
}
func main() {
http.HandleFunc("/send-message", sendMessageHandler)
http.HandleFunc("/status", statusHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
type SendMessageRequest struct {
Phone string `json:"phone"`
Message string `json:"message"`
}
func sendMessageHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req SendMessageRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
resp, err := client.SendText(req.Phone, req.Message)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
}
func statusHandler(w http.ResponseWriter, r *http.Request) {
resp, err := client.Status()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
}Advanced Examples
Retry Logic with Exponential Backoff
import (
"time"
"math"
)
func sendWithRetry(client *whatify.Client, phone, message string, maxRetries int) (*whatify.SendMessageResponse, error) {
var resp *whatify.SendMessageResponse
var err error
for i := 0; i < maxRetries; i++ {
resp, err = client.SendText(phone, message)
if err == nil {
return resp, nil
}
// Check if it's a rate limit error
if apiErr, ok := err.(*whatify.APIError); ok {
if apiErr.StatusCode == 429 && i < maxRetries-1 {
// Exponential backoff
waitTime := time.Duration(math.Pow(2, float64(i))) * time.Second
time.Sleep(waitTime)
continue
}
}
return nil, err
}
return resp, err
}
// Usage
resp, err := sendWithRetry(client, "1234567890", "Hello!", 3)Batch Processing with Goroutines
import "sync"
type SendResult struct {
Phone string
Success bool
Error error
}
func sendBatch(client *whatify.Client, recipients []string, message string) []SendResult {
results := make([]SendResult, len(recipients))
var wg sync.WaitGroup
for i, phone := range recipients {
wg.Add(1)
go func(index int, p string) {
defer wg.Done()
_, err := client.SendText(p, message)
results[index] = SendResult{
Phone: p,
Success: err == nil,
Error: err,
}
}(i, phone)
}
wg.Wait()
return results
}
// Usage
recipients := []string{"1234567890", "0987654321", "5555555555"}
results := sendBatch(client, recipients, "Bulk notification")
for _, r := range results {
if r.Success {
fmt.Printf("Sent to %s\n", r.Phone)
} else {
fmt.Printf("Failed %s: %v\n", r.Phone, r.Error)
}
}Rate Limiter
import (
"sync"
"time"
)
type RateLimiter struct {
maxCalls int
period time.Duration
calls []time.Time
mu sync.Mutex
}
func NewRateLimiter(maxCalls int, period time.Duration) *RateLimiter {
return &RateLimiter{
maxCalls: maxCalls,
period: period,
calls: make([]time.Time, 0),
}
}
func (rl *RateLimiter) Wait() {
rl.mu.Lock()
defer rl.mu.Unlock()
now := time.Now()
// Remove old calls
validCalls := make([]time.Time, 0)
for _, call := range rl.calls {
if now.Sub(call) < rl.period {
validCalls = append(validCalls, call)
}
}
rl.calls = validCalls
// Check if we need to wait
if len(rl.calls) >= rl.maxCalls {
oldestCall := rl.calls[0]
sleepTime := rl.period - now.Sub(oldestCall)
time.Sleep(sleepTime)
}
rl.calls = append(rl.calls, time.Now())
}
// Usage
limiter := NewRateLimiter(100, time.Minute)
for _, phone := range recipients {
limiter.Wait()
client.SendText(phone, "Rate-limited message")
}Worker Pool Pattern
type Job struct {
Phone string
Message string
}
func worker(id int, jobs <-chan Job, results chan<- SendResult, client *whatify.Client) {
for job := range jobs {
_, err := client.SendText(job.Phone, job.Message)
results <- SendResult{
Phone: job.Phone,
Success: err == nil,
Error: err,
}
}
}
func sendWithWorkerPool(client *whatify.Client, jobs []Job, numWorkers int) []SendResult {
jobChan := make(chan Job, len(jobs))
resultChan := make(chan SendResult, len(jobs))
// Start workers
for w := 0; w < numWorkers; w++ {
go worker(w, jobChan, resultChan, client)
}
// Send jobs
for _, job := range jobs {
jobChan <- job
}
close(jobChan)
// Collect results
results := make([]SendResult, 0, len(jobs))
for i := 0; i < len(jobs); i++ {
results = append(results, <-resultChan)
}
return results
}
// Usage
jobs := []Job{
{Phone: "1234567890", Message: "Hello 1"},
{Phone: "0987654321", Message: "Hello 2"},
}
results := sendWithWorkerPool(client, jobs, 5)Type Definitions
type Client struct {
config *Config
}
type Config struct {
APIToken string
APIKey string
}
type Attachment struct {
Type string `json:"type"`
URL string `json:"url"`
Caption string `json:"caption,omitempty"`
Filename string `json:"filename,omitempty"`
}
type SendMessageRequest struct {
To interface{} `json:"to"`
Text string `json:"text,omitempty"`
Attachment *Attachment `json:"attachment,omitempty"`
}Rate Limits
- 100 requests per minute per API token
- 1000 requests per hour per API token
Support
- GitHub: github.com/yourorg/whatify-go
- Documentation: docs.whatify.dev
- Go Package: pkg.go.dev/github.com/yourorg/whatify-go