Paystack SDK for Go
June 20, 2026 ยท View on GitHub
A comprehensive and robust Go SDK for the Paystack API. This library provides a clean, idiomatic Go interface for integrating Paystack payments into your applications.
Features
- Full API Coverage: Comprehensive support for all 24 Paystack services (Transactions, Customers, Transfers, etc.).
- Smart Retries & Rate Limiting: Built-in exponential backoff that respects Paystack's
429 Retry-Afterheaders and strictly avoids retrying non-retryable4xxerrors. - Automatic Idempotency: Automatically generates UUIDv4
Idempotency-Keyheaders for allPOSTandPUTrequests to prevent duplicate charges on network retries. - Generic Pagination Iterators: Best-in-class
paystackapi.Iterator[T]for elegantly fetching paginated list endpoints. - Strongly Typed & Safe: Uses strictly typed enums (
paystackapi.Currency,paystackapi.Channel, etc.) rather than raw strings to prevent runtime errors. - 100% Mockable: Every service client is exposed as a Go
interfaceallowing effortless unit testing viagomock. - Webhook IP Allowlisting: Defense-in-depth webhook signature verification and official IP address validation.
- Zero Dependencies: Relies solely on the Go standard library for a lightweight footprint and maximum security.
Installation
go get github.com/samaasi/paystack-sdk-go/v2@v2.0.0
Usage
Initialization
Initialize the client with your secret key.
package main
import (
"fmt"
"os"
paystack "github.com/samaasi/paystack-sdk-go"
)
func main() {
apiKey := os.Getenv("PAYSTACK_SECRET_KEY")
client := paystack.NewClient(apiKey)
// You can also pass options
// client := paystack.NewClient(apiKey,
// paystack.WithBaseURL("https://api.paystack.co"),
// paystack.WithMaxRetries(5),
// paystack.WithTimeout(10 * time.Second),
// )
}
Configuration
You can configure the client with the following options:
WithBaseURL(url string): Override the default Paystack API base URL.WithMaxRetries(retries int): Set the maximum number of retries for failed requests (default: 3).WithTimeout(timeout time.Duration): Set the timeout for HTTP requests (default: 30s).WithHTTPClient(client *http.Client): Use a custom HTTP client.
Making Requests
Example: Initializing a transaction.
package main
import (
"context"
"fmt"
"log"
"os"
paystack "github.com/samaasi/paystack-sdk-go/v2"
"github.com/samaasi/paystack-sdk-go/v2/paystackapi"
"github.com/samaasi/paystack-sdk-go/service/transactions"
)
func main() {
client := paystack.NewClient(os.Getenv("PAYSTACK_SECRET_KEY"))
req := &transactions.InitializeRequest{
Email: "customer@email.com",
Amount: "500000", // in kobo
Currency: paystackapi.CurrencyNGN,
Metadata: paystackapi.Metadata{
"cart_id": "398",
"custom_fields": []map[string]interface{}{
{
"display_name": "Invoice ID",
"variable_name": "invoice_id",
"value": "INV-001",
},
},
},
}
resp, err := client.Transactions.Initialize(context.Background(), req)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Authorization URL: %s\n", resp.Data.AuthorizationURL)
}
Pagination with Iterators
The SDK provides a generic Iterator pattern to effortlessly fetch records across multiple pages without manually handling Meta cursors or next-page logic.
package main
import (
"context"
"fmt"
"log"
paystack "github.com/samaasi/paystack-sdk-go/v2"
"github.com/samaasi/paystack-sdk-go/v2/paystackapi"
"github.com/samaasi/paystack-sdk-go/service/transactions"
)
func main() {
client := paystack.NewClient("sk_test_...")
ctx := context.Background()
iter := paystackapi.NewIterator(func(ctx context.Context, page, perPage int) (paystackapi.Response[[]transactions.VerifyData], error) {
resp, err := client.Transactions.List(ctx, &transactions.ListTransactionParams{
Page: &page,
PerPage: &perPage,
})
if err != nil {
return paystackapi.Response[[]transactions.VerifyData]{}, err
}
return resp.Response, nil
})
for iter.Next(ctx) {
tx := iter.Value()
fmt.Printf("Transaction ID: %d, Status: %s\n", tx.ID, tx.Status)
}
if err := iter.Err(); err != nil {
log.Fatal("Error during iteration:", err)
}
}
Webhook Verification
Easily and securely verify incoming webhooks from Paystack using HMAC validation and IP Allowlisting.
package main
import (
"log"
"net/http"
"github.com/samaasi/paystack-sdk-go/webhook"
)
func webhookHandler(w http.ResponseWriter, r *http.Request) {
// Defense-in-depth: Verify request originates from Paystack's official IPs
if !webhook.IsFromPaystackIP(r) {
http.Error(w, "Unauthorized IP", http.StatusUnauthorized)
return
}
// Parse and verify the payload signature using your secret key
var event webhook.Event
if err := webhook.Parse(r, "PAYSTACK_SECRET_KEY", &event); err != nil {
log.Printf("Webhook validation failed: %v", err)
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
log.Printf("Received event: %s", event.Event)
w.WriteHeader(http.StatusOK)
}
Idempotency Keys
To prevent duplicate operations, you can pass an Idempotency Key using the context.
import (
"context"
"github.com/samaasi/paystack-sdk-go/paystackapi"
)
func main() {
// ... init client ...
ctx := context.Background()
// Add Idempotency Key to context
ctx = paystackapi.WithIdempotencyKey(ctx, "unique-transaction-id-123")
// The key will be sent in the header as 'Idempotency-Key'
resp, err := client.Transactions.Initialize(ctx, req)
}
Custom Headers
You can also pass arbitrary custom headers via context.
ctx := paystackapi.WithCustomHeader(context.Background(), "X-Custom-Header", "Value")
Supported Services
- Apple Pay
- Bulk Charges
- Charges
- Customers
- Disputes
- Integration
- Miscellaneous (Banks, Countries, etc.)
- Payment Pages
- Payment Requests
- Plans
- Products
- Refunds
- Settlements
- Splits
- Status
- Subaccounts
- Subscriptions
- Terminal
- Transactions
- Transfer Control
- Transfer Recipients
- Transfers
- Verification
- Virtual Accounts
Examples
Runnable examples are available under examples/:
| Example | Description |
|---|---|
initialize_transaction/ | Initialize a transaction and redirect to the Paystack checkout URL |
verify_webhook/ | IP allowlist + HMAC signature verification + event dispatch |
pagination/ | Paginate a transaction list using the generic iterator |
charge_returning_customer/ | Charge an existing authorization with typed error handling |
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
To get started:
- Fork the repository.
- Create a new branch (
git checkout -b feature/amazing-feature). - Commit your changes (
git commit -m 'Add some amazing feature'). - Push to the branch (
git push origin feature/amazing-feature). - Open a Pull Request.
Please ensure you run tests before submitting:
go test ./...
License
This project is licensed under the MIT License - see the LICENSE file for details.