Go SDK github.com/watenga-africa/watenga-go
Go 1.23 or later.
Installation
go get github.com/watenga-africa/watenga-goBefore the first release
go mod edit -replace github.com/watenga-africa/watenga-go=../watenga-payment-network/packages/watenga-goTake a test payment
Use a test secret key (sk_test_…) from the developer console. Test keys never move money: use the test cards and wallet numbers.
client := watenga.New(os.Getenv("WATENGA_SECRET_KEY")) // sk_test_...
co, err := client.Checkout.Create(ctx, watenga.CheckoutCreateParams{
Amount: "25.00",
Currency: "USD",
MerchantTransactionID: "ORD-1001",
ReturnURL: "https://shop.example/return",
})
if err != nil {
return err
}
http.Redirect(w, r, co.PaymentURL, http.StatusSeeOther)Receive the webhook
Verify the Watenga-Signature header against the raw request body before you trust an event. While you rotate the endpoint's signing secret, pass both secrets: either one verifies. On your machine, watenga listen --forward-to <your URL> (the CLI) forwards test events signed with a session secret.
import "github.com/watenga-africa/watenga-go/webhook"
func handleWebhook(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
event, err := webhook.ConstructEvent(body, r.Header.Get(webhook.SignatureHeader), os.Getenv("WATENGA_WEBHOOK_SECRET"))
if err != nil {
http.Error(w, "bad signature", http.StatusBadRequest)
return
}
if event.Type == "payment.capture.completed" {
var txn watenga.Transaction
_ = json.Unmarshal(event.Data.Object, &txn)
// fulfil the order for txn
}
w.WriteHeader(http.StatusOK)
}Errors
Every failed call raises one error type with the stable code, the HTTP status, the request_id to quote to support, the field at fault (param) and the code's page in the error reference.
_, err := client.Refunds.Create(ctx, "txn_...", watenga.RefundCreateParams{Amount: watenga.String("5.00"), Reason: "customer_request"})
if apiErr, ok := watenga.AsError(err); ok {
log.Println(apiErr.Code, apiErr.StatusCode, apiErr.Param, apiErr.RequestID, apiErr.DocURL)
}Retries and idempotency
Network errors, 429 (after Retry-After) and 5xx answers are retried twice with backoff. Every write carries an Idempotency-Key, kept across those retries, so a retry is answered once and never applied twice; checkout.create uses checkout:<merchant_transaction_id>. See Idempotency.
// Every write gets an Idempotency-Key, kept across the SDK's own retries.
// When you retry a call yourself, pass the same key:
client.Refunds.Create(ctx, "txn_...", watenga.RefundCreateParams{Reason: "duplicate"}, watenga.WithIdempotencyKey("refund-ORD-1001"))Pagination
Every list answers one page, { object: "list", data, has_more, next_cursor }; the auto-paginating form reads them all. See Pagination.
page, err := client.Transactions.List(ctx, &watenga.ListParams{Limit: 50, Filters: map[string]string{"status": "completed"}})
// page.Data, page.HasMore, page.NextCursor
for txn, err := range client.Transactions.ListAll(ctx, &watenga.ListParams{Filters: map[string]string{"status": "completed"}}) {
if err != nil {
return err
}
fmt.Println(txn.ID, txn.Amount, txn.Currency)
}Resources
The SDK sends Watenga-Version: 2026-10-29; fields use the API's names (snake_case) and money is a decimal string. The same method names in every language.
| Resource | Methods |
|---|---|
Checkout | Create, GetStatus |
CheckoutSessions | Create, Retrieve, Expire |
Transactions | List, ListAll, Retrieve, GetMobileStatus |
Refunds | Create |
PaymentLinks | Create, List, ListAll, Retrieve, Update, Deactivate, Clone |
Invoices | Create, List, ListAll, Retrieve, Update, Send, Void |
Quotations | Create, List, ListAll, Retrieve, Update, Issue, Void, ConvertToInvoice |
Plans | Create, List, ListAll, Retrieve, Update, Delete |
Subscriptions | Create, List, ListAll, Retrieve, Cancel, Pause, Resume, UpcomingInvoice |
Customers | Create, List, ListAll, Retrieve, Update |
PaymentMethods | Create, List, ListAll, Retrieve, Delete, Charge |
Account | GetBalance, GetProfile, GetAPIKey |
webhook | ConstructEvent, ConstructEventWithOptions, GenerateTestSignature |
Optional request fields are pointers: watenga.String, watenga.Int64, watenga.Bool.
Refunds and payouts
refunds scope (Refunds). Payouts to your bank are dashboard-only, with two-step verification: they are not in the API or the SDKs.