Go SDK
Official Go SDK for PayGate.
Go SDK
The official Go SDK for PayGate provides a convenient way to access the PayGate API from Go applications.
Requirements: Go 1.18 or later.
Installation
go get github.com/paygate/paygate-goQuick Start
package main
import (
"fmt"
"github.com/paygate/paygate-go"
)
func main() {
client := paygate.New("sk_test_...")
// Create a payment
payment, err := client.Payments.Create(&paygate.PaymentParams{
Amount: 5000,
Currency: "GHS",
PaymentMethod: "mobile_money",
Provider: "mtn",
Phone: "0241234567",
})
if err != nil {
panic(err)
}
fmt.Println(payment.ID)
}Configuration
API Key
import (
"os"
"github.com/paygate/paygate-go"
)
// Using environment variable (recommended)
client := paygate.New(os.Getenv("PAYGATE_SECRET_KEY"))
// Or pass directly
client := paygate.New("sk_test_...")Options
client := paygate.New("sk_test_...",
// API version (defaults to latest)
paygate.WithAPIVersion("2024-01-01"),
// Request timeout (default: 30s)
paygate.WithTimeout(60 * time.Second),
// Maximum retries for failed requests (default: 3)
paygate.WithMaxRetries(5),
// Custom base URL (for testing)
paygate.WithBaseURL("https://api.sandbox.paygate.com.gh"),
// Custom HTTP client
paygate.WithHTTPClient(&http.Client{}),
)Payments
Create a Payment
payment, err := client.Payments.Create(&paygate.PaymentParams{
Amount: 5000,
Currency: "GHS",
PaymentMethod: "mobile_money",
Provider: "mtn",
Phone: "0241234567",
Description: "Order #1234",
Metadata: map[string]string{
"order_id": "1234",
"customer_email": "customer@example.com",
},
})
if err != nil {
// Handle error
}
fmt.Println(payment.ID)
fmt.Println(payment.Status) // "pending"Retrieve a Payment
payment, err := client.Payments.Retrieve("pay_abc123")
if err != nil {
// Handle error
}List Payments
// Get a page of payments
params := &paygate.PaymentListParams{
Limit: 10,
Status: "succeeded",
}
payments, err := client.Payments.List(params)
if err != nil {
// Handle error
}
for _, payment := range payments.Data {
fmt.Println(payment.ID)
}
// Check for more pages
if payments.HasMore {
params.StartingAfter = payments.Data[len(payments.Data)-1].ID
nextPage, _ := client.Payments.List(params)
}Cancel a Payment
payment, err := client.Payments.Cancel("pay_abc123")
if err != nil {
// Handle error
}Customers
Create a Customer
customer, err := client.Customers.Create(&paygate.CustomerParams{
Email: "customer@example.com",
Name: "John Doe",
Phone: "0241234567",
Metadata: map[string]string{
"user_id": "123",
},
})Update a Customer
customer, err := client.Customers.Update("cus_abc123", &paygate.CustomerParams{
Name: "Jane Doe",
})Subscriptions
Create a Subscription
subscription, err := client.Subscriptions.Create(&paygate.SubscriptionParams{
Customer: "cus_abc123",
Plan: "plan_xyz789",
PaymentMethod: &paygate.PaymentMethodParams{
Type: "mobile_money",
Phone: "0241234567",
Provider: "mtn",
},
})Cancel a Subscription
// Cancel at period end
_, err := client.Subscriptions.Update("sub_abc123", &paygate.SubscriptionParams{
CancelAtPeriodEnd: true,
})
// Cancel immediately
_, err := client.Subscriptions.Cancel("sub_abc123")Webhooks
Verify Webhook Signature
package main
import (
"encoding/json"
"io"
"net/http"
"github.com/paygate/paygate-go"
"github.com/paygate/paygate-go/webhook"
)
const endpointSecret = "whsec_..."
func webhookHandler(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading body", http.StatusBadRequest)
return
}
signature := r.Header.Get("X-PayGate-Signature")
event, err := webhook.ConstructEvent(payload, signature, endpointSecret)
if err != nil {
http.Error(w, "Invalid signature", http.StatusBadRequest)
return
}
// Handle the event
switch event.Type {
case "payment.succeeded":
var payment paygate.Payment
if err := json.Unmarshal(event.Data.Raw, &payment); err != nil {
http.Error(w, "Error parsing payment", http.StatusBadRequest)
return
}
fmt.Printf("Payment %s succeeded!\n", payment.ID)
// Fulfill the order
case "payment.failed":
fmt.Println("Payment failed")
// Notify customer
case "subscription.created":
fmt.Println("Subscription created")
// Handle new subscription
default:
fmt.Printf("Unhandled event type: %s\n", event.Type)
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]bool{"received": true})
}
func main() {
http.HandleFunc("/webhooks", webhookHandler)
http.ListenAndServe(":3000", nil)
}Gin Framework Example
package main
import (
"github.com/gin-gonic/gin"
"github.com/paygate/paygate-go/webhook"
)
const endpointSecret = "whsec_..."
func main() {
r := gin.Default()
r.POST("/webhooks", func(c *gin.Context) {
payload, _ := c.GetRawData()
signature := c.GetHeader("X-PayGate-Signature")
event, err := webhook.ConstructEvent(payload, signature, endpointSecret)
if err != nil {
c.JSON(400, gin.H{"error": "Invalid signature"})
return
}
switch event.Type {
case "payment.succeeded":
// Handle payment success
case "payment.failed":
// Handle payment failure
}
c.JSON(200, gin.H{"received": true})
})
r.Run(":3000")
}Error Handling
import (
"errors"
"github.com/paygate/paygate-go"
)
client := paygate.New("sk_test_...")
payment, err := client.Payments.Create(&paygate.PaymentParams{
Amount: 5000,
Currency: "GHS",
PaymentMethod: "mobile_money",
Provider: "mtn",
Phone: "0241234567",
})
if err != nil {
var paygateErr *paygate.Error
if errors.As(err, &paygateErr) {
switch paygateErr.Type {
case paygate.ErrorTypeAuthentication:
fmt.Println("Check your API key")
case paygate.ErrorTypeInvalidRequest:
fmt.Printf("Invalid parameter: %s\n", paygateErr.Param)
case paygate.ErrorTypePayment:
switch paygateErr.Code {
case "insufficient_funds":
fmt.Println("Please top up your account")
case "phone_unreachable":
fmt.Println("Please check your phone")
default:
fmt.Println(paygateErr.Message)
}
case paygate.ErrorTypeRateLimit:
time.Sleep(60 * time.Second)
// Retry
case paygate.ErrorTypeAPI:
fmt.Printf("Server error: %s\n", paygateErr.Message)
}
} else {
// Network error or other
fmt.Printf("Unexpected error: %v\n", err)
}
return
}
fmt.Println(payment.ID)Error Types
| Type | Description |
|---|---|
ErrorTypeAuthentication | Invalid API key |
ErrorTypeInvalidRequest | Invalid parameters |
ErrorTypePayment | Payment-specific error |
ErrorTypeRateLimit | Too many requests |
ErrorTypeAPI | Server error |
Idempotency
Use idempotency keys to safely retry requests:
payment, err := client.Payments.Create(&paygate.PaymentParams{
Amount: 5000,
Currency: "GHS",
PaymentMethod: "mobile_money",
Provider: "mtn",
Phone: "0241234567",
}, paygate.WithIdempotencyKey("order_1234_payment"))Context Support
All methods accept a context for cancellation and timeouts:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
payment, err := client.Payments.CreateWithContext(ctx, &paygate.PaymentParams{
Amount: 5000,
Currency: "GHS",
PaymentMethod: "mobile_money",
Provider: "mtn",
Phone: "0241234567",
})Pagination with Iterators
// Iterate through all payments
iter := client.Payments.Iter(&paygate.PaymentListParams{
Status: "succeeded",
})
for iter.Next() {
payment := iter.Payment()
fmt.Println(payment.ID)
}
if err := iter.Err(); err != nil {
// Handle error
}Invoices
Create an Invoice
invoice, err := client.Invoices.Create(&paygate.InvoiceParams{
Customer: "cus_abc123",
Items: []paygate.InvoiceItemParams{
{Description: "Consulting Services", Amount: 50000},
{Description: "Development Work", Amount: 150000},
},
DueDate: "2024-02-15",
Metadata: map[string]string{
"project": "Website Redesign",
},
})Send an Invoice
// Send invoice via email/SMS
err := client.Invoices.Send("inv_abc123")Pay an Invoice
invoice, err := client.Invoices.Pay("inv_abc123", &paygate.InvoicePayParams{
PaymentMethod: &paygate.PaymentMethodParams{
Type: "mobile_money",
Phone: "0241234567",
Provider: "mtn",
},
})List Invoices
invoices, err := client.Invoices.List(&paygate.InvoiceListParams{
Status: "open",
Limit: 10,
})
for _, inv := range invoices.Data {
fmt.Printf("%s: %.2f %s\n", inv.ID, float64(inv.AmountDue)/100, inv.Currency)
}Coupons
Create a Coupon
// Percentage discount
coupon, err := client.Coupons.Create(&paygate.CouponParams{
Code: "SAVE20",
Type: "percent",
PercentOff: 20,
Duration: "repeating",
DurationInMonths: 3,
MaxRedemptions: 100,
})
// Fixed amount discount
coupon, err := client.Coupons.Create(&paygate.CouponParams{
Code: "FLAT50",
Type: "amount",
AmountOff: 5000, // 50 GHS in pesewas
Currency: "GHS",
Duration: "once",
})Validate a Coupon
validation, err := client.Coupons.Validate("SAVE20")
if err != nil {
fmt.Println("Coupon is invalid or expired")
return
}
if validation.Valid {
fmt.Printf("Discount: %d%%\n", validation.PercentOff)
}List Coupons
coupons, err := client.Coupons.List(&paygate.CouponListParams{Limit: 10})
for _, coupon := range coupons.Data {
fmt.Printf("%s: %d/%d redemptions\n", coupon.Code, coupon.TimesRedeemed, coupon.MaxRedemptions)
}QR Codes
Create a Static QR Code
// Reusable payment QR code
qrCode, err := client.QRCodes.Create(&paygate.QRCodeParams{
Type: "static",
Name: "Store Counter QR",
Description: "Scan to pay at checkout",
})
fmt.Printf("QR Image URL: %s\n", qrCode.ImageURL)Create a Dynamic QR Code
// QR code for specific payment
qrCode, err := client.QRCodes.Create(&paygate.QRCodeParams{
Type: "dynamic",
Amount: 5000,
Currency: "GHS",
Description: "Order #1234",
ExpiresIn: 3600, // 1 hour
})
fmt.Printf("QR Image URL: %s\n", qrCode.ImageURL)Retrieve QR Code Status
qrCode, err := client.QRCodes.Retrieve("qr_abc123")
fmt.Printf("Status: %s\n", qrCode.Status)
fmt.Printf("Times Used: %d\n", qrCode.TimesUsed)Reports
Generate a Report
report, err := client.Reports.Create(&paygate.ReportParams{
Type: "payments_summary",
Parameters: map[string]string{
"start_date": "2024-01-01",
"end_date": "2024-01-31",
"group_by": "day",
},
Format: "csv",
})
fmt.Printf("Report ID: %s\n", report.ID)Retrieve Report Status
for {
report, err := client.Reports.Retrieve("report_abc123")
if err != nil {
break
}
if report.Status == "ready" {
fmt.Printf("Download URL: %s\n", report.DownloadURL)
break
}
time.Sleep(5 * time.Second)
}Available Report Types
reportTypes := []string{
"payments_summary",
"payouts_summary",
"settlements",
"disputes",
"customers",
"subscriptions",
"revenue",
}Events
List Events
// Get recent events
events, err := client.Events.List(&paygate.EventListParams{Limit: 20})
for _, event := range events.Data {
fmt.Printf("%s: %s\n", event.Type, event.ID)
}
// Filter by type
paymentEvents, err := client.Events.List(&paygate.EventListParams{
Type: "payment.succeeded",
Limit: 10,
})Retrieve an Event
event, err := client.Events.Retrieve("evt_abc123")
fmt.Printf("Type: %s\n", event.Type)
fmt.Printf("Data: %v\n", event.Data)Event Types
Common event types include:
payment.createdpayment.succeededpayment.failedpayout.createdpayout.succeededcustomer.createdsubscription.createdsubscription.cancelledinvoice.createdinvoice.paiddispute.createddispute.closed
Settings
Settlement Schedule
// Get current settlement schedule
schedule, err := client.Settings.GetSettlementSchedule()
fmt.Printf("Frequency: %s\n", schedule.Frequency)
fmt.Printf("Day of week: %s\n", schedule.DayOfWeek)
// Update settlement schedule
schedule, err = client.Settings.UpdateSettlementSchedule(&paygate.SettlementScheduleParams{
Frequency: "weekly",
DayOfWeek: "friday",
})Transaction Limits
// Get current limits
limits, err := client.Settings.GetTransactionLimits()
fmt.Printf("Min: %d\n", limits.MinAmount)
fmt.Printf("Max: %d\n", limits.MaxAmount)
fmt.Printf("Daily: %d\n", limits.DailyLimit)
// Update limits
limits, err = client.Settings.UpdateTransactionLimits(&paygate.TransactionLimitParams{
MinAmount: 100, // 1 GHS
MaxAmount: 10000000, // 100,000 GHS
DailyLimit: 50000000, // 500,000 GHS
})Two-Factor Authentication
Setup 2FA
// Generate 2FA secret and QR code
setup, err := client.Auth.Setup2FA()
fmt.Printf("Secret: %s\n", setup.Secret)
fmt.Printf("QR Code URL: %s\n", setup.QRCodeURL)
// Display QR code to user for scanningEnable 2FA
// Verify and enable 2FA
result, err := client.Auth.Enable2FA(&paygate.Enable2FAParams{
Code: "123456", // Code from authenticator app
})
if result.Enabled {
fmt.Println("2FA enabled successfully")
fmt.Printf("Backup codes: %v\n", result.BackupCodes)
}Verify 2FA Code
// Verify a 2FA code
result, err := client.Auth.Verify2FA(&paygate.Verify2FAParams{
Code: "123456",
})
if result.Valid {
fmt.Println("Code is valid")
}Disable 2FA
// Disable 2FA (requires current code)
err := client.Auth.Disable2FA(&paygate.Disable2FAParams{
Code: "123456",
})Regenerate Backup Codes
// Get new backup codes
result, err := client.Auth.RegenerateBackupCodes(&paygate.RegenerateBackupCodesParams{
Code: "123456",
})
fmt.Printf("New backup codes: %v\n", result.BackupCodes)