Skip to content

SDK-SPEC-GO — Go SDK Specification

Status: Draft Owner: Platform Engineering Module: github.com/simpaisa/simpaisa-go Runtime: Go 1.22+ Last Updated: 2026-04-03


1. Overview

Official Go SDK for the Simpaisa Payment Gateway. Provides idiomatic, context-aware access to Pay-Ins, Pay-Outs, Remittances, and Cards across PK, BD, NP, and IQ corridors. Handles 270M+ annual transactions at $1B+ volume. Used internally by Simpaisa platform services and offered to merchant integrators. Published via go.dev.

2. Module Path

module github.com/simpaisa/simpaisa-go

Import: import "github.com/simpaisa/simpaisa-go/payin"

3. Package Structure

simpaisa-go/
├── client.go                 # Client struct, constructor, options
├── config.go                 # Config type and defaults
├── payin/
│   ├── client.go             # PayIn operations (Initiate, Verify, Status, List)
│   ├── request.go            # PayInRequest struct
│   └── response.go           # PayInResponse struct
├── payout/
│   ├── client.go             # PayOut operations (Initiate, Status, Batch, Cancel)
│   ├── request.go
│   └── response.go
├── remittance/
│   ├── client.go             # Remittance operations (Quote, Initiate, Status, Beneficiaries)
│   ├── request.go
│   └── response.go
├── cards/
│   ├── client.go             # Cards operations (Pay, Capture, Void, Refund, Tokenise)
│   ├── request.go
│   └── response.go
├── webhook/
│   ├── verifier.go           # HMAC-SHA256 webhook verification
│   └── event.go              # WebhookEvent type
├── auth/
│   ├── rsa.go                # RSAAuthProvider — PEM loading, request signing
│   └── auth.go               # AuthProvider interface
├── errors.go                 # Error types and sentinel values
├── retry/
│   └── policy.go             # Exponential backoff with jitter
├── idempotency/
│   └── generator.go          # UUID v7 key generation
├── internal/
│   ├── transport.go          # HTTP transport with auth, retry, idempotency
│   └── json.go               # JSON helpers
├── go.mod
├── go.sum
└── Makefile

4. Authentication — RSAAuthProvider

  • Load merchant private key from PEM file via crypto/x509.ParsePKCS8PrivateKey
  • Sign request body with crypto/rsa.SignPKCS1v15 using SHA-256
  • Attach X-Simpaisa-Signature and X-Simpaisa-Merchant-Id headers
  • Implement AuthProvider interface for extensibility
  • Support key rotation via slice of key paths
auth, err := auth.NewRSAProvider(
    auth.WithMerchantID("MCH-001"),
    auth.WithPrivateKeyFile("./keys/merchant.pem"),
)

5. Context-Aware Design

  • ALL public methods SHALL accept context.Context as first parameter
  • Respect context cancellation and deadlines
  • Propagate trace context via go.opentelemetry.io/otel when available
  • No background goroutines without explicit lifecycle management
result, err := client.PayIn.Initiate(ctx, &payin.Request{
    Amount:   5000,
    Currency: "PKR",
    Channel:  "EASYPAISA",
})

6. WebhookVerifier

  • Verify X-Simpaisa-Webhook-Signature using crypto/hmac with SHA-256
  • Verify(payload []byte, signature string) error
  • Constant-time comparison via hmac.Equal()
  • Replay protection: validate timestamp header within tolerance (default 300s)
  • Return ErrWebhookVerification on failure

7. Retry with Backoff

  • Exponential backoff with jitter (base 200ms, max 30s)
  • Configurable max retries (default 3)
  • Retry on: 429, 502, 503, 504, net.Error (temporary)
  • Never retry: 400, 401, 403, 404, 409, 422
  • Respect Retry-After header
  • OnRetry callback function for observability
  • Context cancellation stops retries immediately

8. Idiomatic Go Patterns

  • Functional options pattern for configuration: WithTimeout(), WithRetries()
  • Error values (not exceptions): return error from all fallible operations
  • Sentinel errors: ErrAuthentication, ErrValidation, ErrRateLimit, ErrTimeout
  • errors.Is() and errors.As() compatible
  • No generics abuse — use concrete types
  • io.Reader/io.Writer where appropriate
  • Struct embedding for composition

9. Error Handling

var (
    ErrAuthentication     // 401/403 responses
    ErrValidation         // 400/422 with field details
    ErrRateLimit          // 429 with RetryAfter
    ErrTimeout            // request/connection timeout
    ErrIdempotency        // conflicting idempotency key
    ErrNetwork            // connection/DNS failures
    ErrWebhookVerification // signature mismatch
)

// SimPaisaError wraps all errors with metadata
type SimPaisaError struct {
    Code      string
    Message   string
    StatusCode int
    RequestID string
    Retryable bool
    Err       error  // wrapped error for errors.Is/As
}

10. Configuration

client, err := simpaisa.NewClient(
    simpaisa.WithEnvironment(simpaisa.Sandbox),  // Sandbox or Production
    simpaisa.WithMerchantID("MCH-001"),
    simpaisa.WithPrivateKeyFile("./keys/merchant.pem"),
    simpaisa.WithTimeout(30 * time.Second),      // default 30s
    simpaisa.WithMaxRetries(3),                  // default 3
    simpaisa.WithHTTPClient(customClient),       // optional
    simpaisa.WithLogger(slog.Default()),         // optional, log/slog
)

11. Example Usage

package main

import (
    "context"
    "log"

    "github.com/simpaisa/simpaisa-go"
    "github.com/simpaisa/simpaisa-go/payin"
    "github.com/simpaisa/simpaisa-go/webhook"
)

func main() {
    client, err := simpaisa.NewClient(
        simpaisa.WithEnvironment(simpaisa.Sandbox),
        simpaisa.WithMerchantID("MCH-001"),
        simpaisa.WithPrivateKeyFile("./keys/merchant.pem"),
    )
    if err != nil {
        log.Fatal(err)
    }

    // Pay-In
    result, err := client.PayIn.Initiate(context.Background(), &payin.Request{
        Amount:         5000,
        Currency:       "PKR",
        Channel:        "EASYPAISA",
        CustomerMSISDN: "03001234567",
        CallbackURL:    "https://merchant.com/webhook",
    })

    // Webhook verification
    verifier := webhook.NewVerifier("whsec_...")
    err = verifier.Verify(rawBody, signatureHeader)
}

12. Build and Publish

  • Test: go test ./... with race detector (-race)
  • Linting: golangci-lint (golint, govet, staticcheck, errcheck, gosec)
  • CI: Bitbucket Pipelines — lint → test → vet → build
  • Publish: Tag-based releases; go.dev indexes automatically
  • Versioning: Semantic versioning via git tags (v1.x.x)
  • Go compatibility: Tested on latest two Go releases

13. Dependencies

  • Standard library only for core functionality (net/http, crypto/*, encoding/json)
  • Optional: go.opentelemetry.io/otel for tracing
  • Zero required third-party dependencies for the base SDK
  • log/slog for structured logging (Go 1.21+)

14. Testing Requirements

  • Unit tests for every exported function (>90% coverage)
  • Integration tests against sandbox environment (build-tagged)
  • Table-driven tests following Go conventions
  • Webhook verification round-trip tests
  • Retry behaviour tests with httptest.Server
  • Race condition tests (-race flag in CI)
  • Fuzz tests for webhook verification and JSON parsing

15. Documentation

  • GoDoc comments on all exported types, functions, and methods
  • Package-level doc.go in each package
  • README with quickstart and corridor-specific examples
  • Examples as Example* test functions (appear on go.dev)
  • CHANGELOG following Keep a Changelog format