paystack

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2026 License: MIT Imports: 16 Imported by: 0

README

paystack-go

CI Go Reference Go Report Card

A production-grade Go SDK for Paystack — the African payments gateway that merchants use to accept card, bank, USSD, mobile-money, and transfer payments across Nigeria, Ghana, South Africa, Kenya, and Côte d'Ivoire.

Built against the Paystack REST API for teams that need to embed Paystack inside a larger platform — billing systems, marketplaces, banking-as-a-service, ERPs, fintech cores — where correctness, testability, observability, and interface stability matter more than convenience.

Useful links:

Status: pre-1.0. Interfaces are stable on main but minor versions may introduce additive changes to request/response structs. See Versioning for the compatibility policy.

Why this SDK

Designed for enterprise systems rather than one-off scripts. Every design decision maps to a concrete operational concern:

Concern How it's addressed
Testability Every resource sits behind a Transactor / Customeror / … interface. Swap the Backend in tests — no live HTTP.
Idempotency Params.IdempotencyKey is forwarded as a header on every write, so safe to retry across crashes.
Observability Logger and LeveledLogger seams route SDK logs into your platform's logging stack (zap, slog, logrus, zerolog).
Auditable errors One *Error type with stable Code constants (ErrCodeInvalidKey, ErrCodeRateLimited, …), populated Fields on validation errors, and parsed RetryAfter. Works with errors.As.
No hidden retries The SDK never retries. You own the policy — pair it with your existing circuit-breaker / retry library.
No currency surprises Amounts are int64 in kobo end-to-end. No silent conversion, no float.
Constant-time crypto Webhook Verify uses hmac.Equal; body reads are LimitReader-capped to defend against oversized payloads.
Stable contract ClientInterface, Backend, service interfaces, and Event never break without a major bump — safe to depend on.
Framework-agnostic Core SDK has one production dependency (go-querystring). Gin/Fiber/Echo adapters ship as separate modules so you only pay for what you use.
Context-first Every call takes context.Context — timeouts and cancellation propagate through your request graph.
Compliance surface SDK never stores card data or keys at rest. Everything is stateless; caller owns the vault.

Design

  • paystack-go is the transport- and API-faithful core.
  • paystackgin, paystackfiber, paystackecho are thin framework adapters that import this package's interfaces, never its concrete types.

The SDK represents the Paystack API faithfully. Retry strategies, currency conversion, framework lifecycle, and business logic belong to the caller or an integration package — not the SDK.

Installation

go get github.com/saphemmy/paystack-go

Go 1.22 or later.

Quick start

package main

import (
    "context"
    "log"

    paystack "github.com/saphemmy/paystack-go"
)

func main() {
    client, err := paystack.New("sk_test_xxx")
    if err != nil {
        log.Fatal(err)
    }

    tx, err := client.Transaction().Initialize(context.Background(), &paystack.TransactionInitializeParams{
        Email:  "customer@example.com",
        Amount: 500000, // kobo — 5,000.00 NGN
    })
    if err != nil {
        log.Fatal(err)
    }

    log.Println(tx.AuthorizationURL)
}

Amounts are in kobo (1 NGN = 100 kobo). This is never silently converted.

Framework integrations

Framework Package
Gin github.com/saphemmy/paystack-go/paystackgin
Fiber github.com/saphemmy/paystack-go/paystackfiber
Echo github.com/saphemmy/paystack-go/paystackecho

Each is a separate Go module, importable independently.

Error handling

Every non-2xx response is returned as a *paystack.Error. Callers switch on err.Code:

tx, err := client.Transaction().Verify(ctx, reference)
var pErr *paystack.Error
if errors.As(err, &pErr) {
    switch pErr.Code {
    case paystack.ErrCodeRateLimited:
        time.Sleep(pErr.RetryAfter)
        // retry — the SDK never retries for you
    case paystack.ErrCodeInvalidRequest:
        for field, msg := range pErr.Fields {
            log.Printf("%s: %s", field, msg)
        }
    }
}

Webhooks

import "github.com/saphemmy/paystack-go"

func handler(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(io.LimitReader(r.Body, 1<<20))
    if !paystack.Verify(body, r.Header.Get("x-paystack-signature"), secret) {
        http.Error(w, "invalid signature", http.StatusUnauthorized)
        return
    }
    event, err := paystack.ParseEvent(body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    switch event.Type {
    case paystack.EventChargeSuccess:
        var charge paystack.Charge
        _ = json.Unmarshal(event.Data, &charge)
        // ...
    }
    w.WriteHeader(http.StatusOK)
}

Framework packages ship a WebhookHandler that wraps verification, body size limiting, and parsing.

Testing

The SDK exposes a Backend interface so you never need to hit the live API in tests. internal/testutil ships MockBackend and FixtureBackend — these are used by the SDK's own tests and are not part of the public API.

For downstream tests, swap the Backend via paystack.WithBackend(...).

Run the suite:

go test ./...
go test -race ./...
go test -cover ./...

Integration tests against the Paystack sandbox live behind the integration build tag:

PAYSTACK_TEST_KEY=sk_test_xxx go test -tags=integration ./...

Versioning

  • Stable surfaceClientInterface, Backend, service interfaces, Event, Logger, LeveledLogger. Breaking changes require a major bump.
  • Internal — concrete service structs and HTTPBackend internals may change between minor versions.
  • Request/response structs — additive in minor versions. Fields are never removed or renamed without a major bump.

See CHANGELOG.md for release history.

Contributing

Pull requests are welcome. Please read CONTRIBUTING.md and our Code of Conduct first.

To report a security issue, see SECURITY.md.

License

MIT © Oluwafemi Sosami

Documentation

Overview

Package paystack is the Go SDK for the Paystack payments API.

It is a lean, transport-faithful client. The SDK represents the HTTP API exactly; retry strategies, currency conversion, and framework lifecycle belong to the caller or to one of the framework integration packages (paystackgin, paystackfiber, paystackecho).

Getting started

Construct a client with your secret key. Validation happens up front — keys must begin with sk_test_ or sk_live_.

client, err := paystack.New("sk_test_xxx")
if err != nil {
    log.Fatal(err)
}

tx, err := client.Transaction().Initialize(ctx, &paystack.TransactionInitializeParams{
    Email:  "customer@example.com",
    Amount: 500000, // kobo: 5,000.00 NGN
})

Amounts

All monetary values are int64 in kobo (1 NGN = 100 kobo). The SDK never performs currency conversion.

Errors

Every non-2xx response is returned as a *Error. Callers branch on Code:

var pErr *paystack.Error
if errors.As(err, &pErr) {
    switch pErr.Code {
    case paystack.ErrCodeRateLimited:
        time.Sleep(pErr.RetryAfter)
    case paystack.ErrCodeInvalidRequest:
        for field, msg := range pErr.Fields {
            log.Printf("%s: %s", field, msg)
        }
    }
}

Extensibility

The SDK exposes stable interfaces — ClientInterface, Backend, the per-resource service interfaces (Transactor, Customeror, Planner, Subscriber, Transferor, Charger, Refunder), Logger, and LeveledLogger — so callers can wrap, instrument, or mock any layer without forking the SDK.

Webhooks

Verify uses hmac.Equal for constant-time comparison; ParseEvent returns a raw Event whose Data field the caller unmarshals into the concrete type.

Index

Constants

View Source
const (
	// DefaultBaseURL is the production Paystack API host.
	DefaultBaseURL = "https://api.paystack.co"
)
View Source
const MaxWebhookBodyBytes = 1 << 20 // 1 MiB

MaxWebhookBodyBytes caps the payload ParseWebhook will read from an http.Request body. Paystack events are kilobytes at most; anything larger is treated as hostile.

View Source
const WebhookSignatureHeader = "X-Paystack-Signature"

WebhookSignatureHeader is the HTTP header Paystack uses to transmit the HMAC signature of the webhook body.

Variables

View Source
var ErrInvalidKey = errors.New("paystack: secret key must start with sk_test_ or sk_live_")

ErrInvalidKey is returned by New when the supplied secret key does not have a recognised Paystack prefix.

View Source
var ErrInvalidSignature = errors.New("paystack: invalid webhook signature")

ErrInvalidSignature is returned by ParseWebhook when the body's HMAC does not match the header.

Key is an optional package-level secret key. Setting it is not required — callers should prefer passing the key to New — but it exists for parity with the Paystack client conventions in other languages.

Functions

func Bool

func Bool(b bool) *bool

Bool returns a pointer to b.

func Float64

func Float64(f float64) *float64

Float64 returns a pointer to f.

func Int

func Int(n int) *int

Int returns a pointer to n.

func Int64

func Int64(n int64) *int64

Int64 returns a pointer to n.

func String

func String(s string) *string

String returns a pointer to s. Use it to populate optional string fields without having to declare a variable.

func Verify

func Verify(body []byte, sig string, secret []byte) bool

Verify reports whether sig matches the HMAC-SHA512 of body under secret. Uses hmac.Equal to prevent timing attacks. Accepts hex-encoded signatures in either case.

Types

type Authorization

type Authorization struct {
	AuthorizationCode string `json:"authorization_code"`
	Bin               string `json:"bin"`
	Last4             string `json:"last4"`
	ExpMonth          string `json:"exp_month"`
	ExpYear           string `json:"exp_year"`
	Channel           string `json:"channel"`
	CardType          string `json:"card_type"`
	Bank              string `json:"bank"`
	CountryCode       string `json:"country_code"`
	Brand             string `json:"brand"`
	Reusable          bool   `json:"reusable"`
	Signature         string `json:"signature"`
	AccountName       string `json:"account_name"`
}

Authorization is Paystack's saved-card representation. Returned embedded in Transaction, Charge, and Customer payloads whenever a reusable token exists.

type Backend

type Backend interface {
	Call(ctx context.Context, method, path string, params, out interface{}) error
	CallRaw(ctx context.Context, method, path string, params interface{}) (*http.Response, error)
}

Backend is the HTTP contract the SDK depends on. Swap it entirely for proxies, recording backends, or test doubles.

type BackendConfig

type BackendConfig struct {
	HTTPClient    *http.Client
	BaseURL       string
	Logger        Logger
	LeveledLogger LeveledLogger
}

BackendConfig configures an HTTPBackend. All fields are optional; a nil config yields the default production client.

type ChargeBank

type ChargeBank struct {
	Code          string `json:"code"`
	AccountNumber string `json:"account_number"`
}

ChargeBank represents direct bank debit.

type ChargeCard

type ChargeCard struct {
	Number   string `json:"number"`
	CVV      string `json:"cvv"`
	ExpMonth string `json:"expiry_month"`
	ExpYear  string `json:"expiry_year"`
}

ChargeCard represents raw card details. Only used by merchants who have PCI scope; most callers should use authorization_code or the checkout flow.

type ChargeCreateParams

type ChargeCreateParams struct {
	Params
	Email             string      `json:"email"`
	Amount            int64       `json:"amount"`
	Currency          *string     `json:"currency,omitempty"`
	Reference         *string     `json:"reference,omitempty"`
	AuthorizationCode *string     `json:"authorization_code,omitempty"`
	PIN               *string     `json:"pin,omitempty"`
	Card              *ChargeCard `json:"card,omitempty"`
	Bank              *ChargeBank `json:"bank,omitempty"`
	MobileMoney       *ChargeMoMo `json:"mobile_money,omitempty"`
	Birthday          *string     `json:"birthday,omitempty"`
	DeviceID          *string     `json:"device_id,omitempty"`
}

ChargeCreateParams is POST /charge. Provide one of authorization_code, bank, card, or mobile_money.

type ChargeMoMo

type ChargeMoMo struct {
	Phone    string `json:"phone"`
	Provider string `json:"provider"`
}

ChargeMoMo represents mobile-money debit.

type ChargeResult

type ChargeResult struct {
	Reference       string         `json:"reference"`
	Status          string         `json:"status"`
	Display         string         `json:"display_text"`
	Message         string         `json:"message"`
	GatewayResponse string         `json:"gateway_response"`
	Amount          int64          `json:"amount"`
	Currency        string         `json:"currency"`
	Channel         string         `json:"channel"`
	PaidAt          Time           `json:"paid_at"`
	CreatedAt       Time           `json:"created_at"`
	Customer        *CustomerLite  `json:"customer,omitempty"`
	Authorization   *Authorization `json:"authorization,omitempty"`
	Metadata        Metadata       `json:"metadata,omitempty"`
}

ChargeResult is the progressively-updating charge state Paystack returns from every /charge endpoint. Callers check Status and, if further input is required (send_pin, send_otp, send_phone, send_birthday), prompt the customer then submit through the corresponding SubmitXxx method.

type ChargeService

type ChargeService struct {
	// contains filtered or unexported fields
}

ChargeService is the default Charger implementation.

func (*ChargeService) CheckPending

func (s *ChargeService) CheckPending(ctx context.Context, reference string) (*ChargeResult, error)

CheckPending re-polls a charge that remained in a pending state.

func (*ChargeService) Create

Create initiates a charge. Depending on Status the caller may need to invoke SubmitPin, SubmitOTP, SubmitPhone, or SubmitBirthday before the charge finalises.

func (*ChargeService) SubmitBirthday

SubmitBirthday completes a charge that is awaiting a birthday.

func (*ChargeService) SubmitOTP

SubmitOTP completes a charge that is awaiting an OTP.

func (*ChargeService) SubmitPhone

SubmitPhone completes a charge that is awaiting a phone number.

func (*ChargeService) SubmitPin

SubmitPin completes a charge that is awaiting a card PIN.

type ChargeSubmitBirthdayParams

type ChargeSubmitBirthdayParams struct {
	Params
	Reference string `json:"reference"`
	Birthday  string `json:"birthday"`
}

ChargeSubmitBirthdayParams is POST /charge/submit_birthday.

type ChargeSubmitOTPParams

type ChargeSubmitOTPParams struct {
	Params
	Reference string `json:"reference"`
	OTP       string `json:"otp"`
}

ChargeSubmitOTPParams is POST /charge/submit_otp.

type ChargeSubmitPhoneParams

type ChargeSubmitPhoneParams struct {
	Params
	Reference string `json:"reference"`
	Phone     string `json:"phone"`
}

ChargeSubmitPhoneParams is POST /charge/submit_phone.

type ChargeSubmitPinParams

type ChargeSubmitPinParams struct {
	Params
	Reference string `json:"reference"`
	PIN       string `json:"pin"`
}

ChargeSubmitPinParams is POST /charge/submit_pin.

type Charger

type Charger interface {
	Create(ctx context.Context, params *ChargeCreateParams) (*ChargeResult, error)
	SubmitPin(ctx context.Context, params *ChargeSubmitPinParams) (*ChargeResult, error)
	SubmitOTP(ctx context.Context, params *ChargeSubmitOTPParams) (*ChargeResult, error)
	SubmitPhone(ctx context.Context, params *ChargeSubmitPhoneParams) (*ChargeResult, error)
	SubmitBirthday(ctx context.Context, params *ChargeSubmitBirthdayParams) (*ChargeResult, error)
	CheckPending(ctx context.Context, reference string) (*ChargeResult, error)
}

Charger is the contract for /charge endpoints.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is the concrete ClientInterface implementation. New returns it as ClientInterface; callers rarely need to reference this type directly.

func (*Client) Backend

func (c *Client) Backend() Backend

Backend returns the underlying transport. Exposed for advanced callers.

func (*Client) Charge

func (c *Client) Charge() Charger

Charge returns the service for /charge endpoints.

func (*Client) Customer

func (c *Client) Customer() Customeror

Customer returns the service for /customer endpoints.

func (*Client) Plan

func (c *Client) Plan() Planner

Plan returns the service for /plan endpoints.

func (*Client) Refund

func (c *Client) Refund() Refunder

Refund returns the service for /refund endpoints.

func (*Client) Subscription

func (c *Client) Subscription() Subscriber

Subscription returns the service for /subscription endpoints.

func (*Client) Transaction

func (c *Client) Transaction() Transactor

Transaction returns the service for /transaction endpoints.

func (*Client) Transfer

func (c *Client) Transfer() Transferor

Transfer returns the service for /transfer endpoints.

type ClientInterface

type ClientInterface interface {
	Transaction() Transactor
	Customer() Customeror
	Plan() Planner
	Subscription() Subscriber
	Transfer() Transferor
	Charge() Charger
	Refund() Refunder

	// Backend returns the underlying Backend. Useful for tests that swap it
	// at runtime, or for advanced callers issuing requests against endpoints
	// the SDK has not yet modelled.
	Backend() Backend
}

ClientInterface is the top-level contract implemented by the concrete *Client. Framework integration packages and application code should depend on this interface rather than the concrete type.

func New

func New(secretKey string, opts ...Option) (ClientInterface, error)

New builds a ClientInterface, validating the secret key up front. A test key must start with sk_test_ and a live key with sk_live_; anything else is rejected with ErrInvalidKey.

type CurrencyVolume

type CurrencyVolume struct {
	Currency string `json:"currency"`
	Amount   int64  `json:"amount"`
}

CurrencyVolume is one row of TransactionTotals.TotalVolumeByCurrency.

type Customer

type Customer struct {
	ID              int64           `json:"id"`
	Domain          string          `json:"domain"`
	CustomerCode    string          `json:"customer_code"`
	Email           string          `json:"email"`
	FirstName       string          `json:"first_name"`
	LastName        string          `json:"last_name"`
	Phone           string          `json:"phone"`
	RiskAction      string          `json:"risk_action"`
	CreatedAt       Time            `json:"createdAt"`
	UpdatedAt       Time            `json:"updatedAt"`
	Metadata        Metadata        `json:"metadata,omitempty"`
	Authorizations  []Authorization `json:"authorizations,omitempty"`
	Transactions    []Transaction   `json:"transactions,omitempty"`
	Subscriptions   []Subscription  `json:"subscriptions,omitempty"`
	TotalVolume     int64           `json:"total_volume"`
	Identified      bool            `json:"identified"`
	IdentifiedValue Metadata        `json:"identifications,omitempty"`
}

Customer is the full customer record returned by Paystack.

type CustomerCreateParams

type CustomerCreateParams struct {
	Params
	Email     string  `json:"email"`
	FirstName *string `json:"first_name,omitempty"`
	LastName  *string `json:"last_name,omitempty"`
	Phone     *string `json:"phone,omitempty"`
}

CustomerCreateParams is the payload for POST /customer.

type CustomerListParams

type CustomerListParams struct {
	ListParams
}

CustomerListParams is the query for GET /customer.

type CustomerLite

type CustomerLite struct {
	ID           int64  `json:"id"`
	CustomerCode string `json:"customer_code"`
	Email        string `json:"email"`
	FirstName    string `json:"first_name"`
	LastName     string `json:"last_name"`
	Phone        string `json:"phone"`
}

CustomerLite is the reduced Customer shape embedded in other resources (transactions, subscriptions, refunds). Fetches of the full Customer record return the Customer type in customer.go.

type CustomerRiskActionParams

type CustomerRiskActionParams struct {
	Params
	Customer   string `json:"customer"`
	RiskAction string `json:"risk_action"`
}

CustomerRiskActionParams is the payload for POST /customer/set_risk_action.

type CustomerService

type CustomerService struct {
	// contains filtered or unexported fields
}

CustomerService is the default Customeror implementation.

func (*CustomerService) Create

Create registers a new customer.

func (*CustomerService) DeactivateAuthorization

func (s *CustomerService) DeactivateAuthorization(ctx context.Context, code string) error

DeactivateAuthorization disables a saved authorization so it can no longer be charged.

func (*CustomerService) Fetch

func (s *CustomerService) Fetch(ctx context.Context, emailOrCode string) (*Customer, error)

Fetch returns a customer by either email or customer_code.

func (*CustomerService) List

List returns a page of customers.

func (*CustomerService) SetRiskAction

func (s *CustomerService) SetRiskAction(ctx context.Context, p *CustomerRiskActionParams) (*Customer, error)

SetRiskAction flags a customer as allow, deny, or default.

func (*CustomerService) Update

Update edits a customer identified by customer_code.

type CustomerUpdateParams

type CustomerUpdateParams struct {
	Params
	FirstName *string `json:"first_name,omitempty"`
	LastName  *string `json:"last_name,omitempty"`
	Phone     *string `json:"phone,omitempty"`
}

CustomerUpdateParams is the payload for PUT /customer/:code.

type Customeror

type Customeror interface {
	Create(ctx context.Context, params *CustomerCreateParams) (*Customer, error)
	Fetch(ctx context.Context, emailOrCode string) (*Customer, error)
	List(ctx context.Context, params *CustomerListParams) ([]Customer, Meta, error)
	Update(ctx context.Context, code string, params *CustomerUpdateParams) (*Customer, error)
	SetRiskAction(ctx context.Context, params *CustomerRiskActionParams) (*Customer, error)
	DeactivateAuthorization(ctx context.Context, authorizationCode string) error
}

Customeror is the contract for /customer endpoints.

type Error

type Error struct {
	Code       ErrorCode
	Message    string
	StatusCode int
	Fields     map[string]string
	RetryAfter time.Duration
	RawBody    []byte
}

Error is the single error type returned for every non-2xx response from the Paystack API. Callers switch on Code to branch behaviour. Works with errors.As.

func ParseError

func ParseError(resp *http.Response, body []byte) *Error

ParseError converts a non-2xx HTTP response into a *Error. body is the already-read response body; caller is responsible for draining the response. Exposed for authors of custom Backend implementations.

func (*Error) Error

func (e *Error) Error() string

type ErrorCode

type ErrorCode string

ErrorCode classifies errors returned by the Paystack API.

const (
	ErrCodeInvalidKey     ErrorCode = "invalid_key"
	ErrCodeInvalidRequest ErrorCode = "invalid_request"
	ErrCodeNotFound       ErrorCode = "not_found"
	ErrCodeRateLimited    ErrorCode = "rate_limited"
	ErrCodeServerError    ErrorCode = "server_error"
)

type Event

type Event struct {
	Type EventType       `json:"event"`
	Data json.RawMessage `json:"data"`
}

Event is the wire shape of a Paystack webhook. Data is the raw JSON of the event's `data` object; callers unmarshal it into the concrete type they expect. No typed unions — keeps the API stable as Paystack adds fields.

func ParseEvent

func ParseEvent(body []byte) (*Event, error)

ParseEvent decodes a webhook body into an Event. The caller must have already verified the signature with Verify.

func ParseWebhook

func ParseWebhook(r *http.Request, secret []byte) (*Event, error)

ParseWebhook reads, size-limits, verifies, and parses a webhook request in one call. It is the recommended entry point for http.Handler-based servers that aren't using one of the framework integration packages.

The caller is responsible for writing the HTTP response. ParseWebhook never closes r.Body — that remains the caller's contract with the net/http server.

type EventType

type EventType string

EventType is a Paystack webhook event name.

const (
	EventChargeSuccess             EventType = "charge.success"
	EventChargeDisputeCreate       EventType = "charge.dispute.create"
	EventChargeDisputeRemind       EventType = "charge.dispute.remind"
	EventChargeDisputeResolve      EventType = "charge.dispute.resolve"
	EventTransferSuccess           EventType = "transfer.success"
	EventTransferFailed            EventType = "transfer.failed"
	EventTransferReversed          EventType = "transfer.reversed"
	EventSubscriptionCreate        EventType = "subscription.create"
	EventSubscriptionDisable       EventType = "subscription.disable"
	EventSubscriptionNotRenew      EventType = "subscription.not_renew"
	EventSubscriptionExpiringCards EventType = "subscription.expiring_cards"
	EventInvoiceCreate             EventType = "invoice.create"
	EventInvoiceUpdate             EventType = "invoice.update"
	EventInvoicePaymentFailed      EventType = "invoice.payment_failed"
	EventPaymentRequestPending     EventType = "paymentrequest.pending"
	EventPaymentRequestSuccess     EventType = "paymentrequest.success"
	EventCustomerIdentification    EventType = "customeridentification.success"
	EventDedicatedAccountAssign    EventType = "dedicatedaccount.assign.success"
	EventRefundProcessed           EventType = "refund.processed"
	EventRefundFailed              EventType = "refund.failed"
)

The full set of Paystack webhook events supported by this SDK. Callers should switch on Event.Type and unmarshal Event.Data into the concrete payload they expect.

type HTTPBackend

type HTTPBackend struct {
	// contains filtered or unexported fields
}

HTTPBackend is the default Backend implementation. It is exported so integration packages and advanced callers can embed or wrap it.

func NewHTTPBackend

func NewHTTPBackend(key string, cfg *BackendConfig) *HTTPBackend

NewHTTPBackend builds an HTTPBackend. cfg may be nil.

func (*HTTPBackend) Call

func (b *HTTPBackend) Call(ctx context.Context, method, path string, params, out interface{}) error

Call issues an HTTP request, decodes the JSON response into out, and converts non-2xx responses to *Error. A nil out discards the body.

func (*HTTPBackend) CallRaw

func (b *HTTPBackend) CallRaw(ctx context.Context, method, path string, params interface{}) (*http.Response, error)

CallRaw returns the live *http.Response. The caller owns resp.Body and must close it. Useful for streaming or inspecting headers.

type LeveledLogger

type LeveledLogger interface {
	Debugf(format string, args ...interface{})
	Infof(format string, args ...interface{})
	Warnf(format string, args ...interface{})
	Errorf(format string, args ...interface{})
}

LeveledLogger lets integration packages route SDK logs into their framework's level-aware logger (zap, zerolog, slog, logrus, etc).

type ListParams

type ListParams struct {
	Params  `json:"-" url:"-"`
	PerPage *int  `json:"-" url:"perPage,omitempty"`
	Page    *int  `json:"-" url:"page,omitempty"`
	From    *Time `json:"-" url:"from,omitempty"`
	To      *Time `json:"-" url:"to,omitempty"`
}

ListParams is embedded in list-endpoint request structs. All fields are optional; nil leaves the parameter off the query string entirely.

type ListResponse

type ListResponse[T any] struct {
	Status  bool   `json:"status"`
	Message string `json:"message"`
	Data    []T    `json:"data"`
	Meta    Meta   `json:"meta"`
}

ListResponse is the generic envelope every Paystack list endpoint returns. An empty Data slice with Meta.Total > 0 is a legitimate response (the caller paged past the end) and is never treated as an error.

type Logger

type Logger interface {
	Printf(format string, args ...interface{})
}

Logger is the simplest logger contract the SDK accepts. Callers that want structured output should implement LeveledLogger instead.

type Meta

type Meta struct {
	Total     int `json:"total"`
	Skipped   int `json:"skipped"`
	PerPage   int `json:"perPage"`
	Page      int `json:"page"`
	PageCount int `json:"pageCount"`
}

Meta is the pagination envelope Paystack returns on list endpoints. It is exposed raw — the SDK never hides pagination state.

type Metadata

type Metadata = json.RawMessage

Metadata is the flexible blob Paystack echoes back on any resource that accepted Params.Metadata at creation time. Callers unmarshal it into their own struct.

type Option

type Option func(*clientOptions)

Option configures a Client built by New. Options are applied in order.

func WithBackend

func WithBackend(b Backend) Option

WithBackend substitutes the entire Backend. Use it for custom transports, recording backends, or to drop in a test double.

func WithBaseURL

func WithBaseURL(url string) Option

WithBaseURL points the default HTTPBackend at a non-production host. Ignored when WithBackend is also supplied.

func WithHTTPClient

func WithHTTPClient(c *http.Client) Option

WithHTTPClient overrides the http.Client used by the default HTTPBackend. Ignored when WithBackend is also supplied.

func WithLeveledLogger

func WithLeveledLogger(l LeveledLogger) Option

WithLeveledLogger wires a structured logger into the default HTTPBackend. Takes precedence over WithLogger when both are set.

func WithLogger

func WithLogger(l Logger) Option

WithLogger wires a Printf-style logger into the default HTTPBackend. Ignored when WithBackend is also supplied.

type Params

type Params struct {
	// IdempotencyKey, when set, is forwarded on the Idempotency-Key header
	// for writes. The SDK never generates one automatically.
	IdempotencyKey *string `json:"-"`

	// Metadata attaches an arbitrary JSON object to a resource. Paystack
	// echoes it back on fetches and webhooks.
	Metadata map[string]interface{} `json:"metadata,omitempty"`
}

Params is the base embedded into every request struct. It carries values that are sent as HTTP headers or top-level metadata, never as plain body fields.

type Plan

type Plan struct {
	ID                int64    `json:"id"`
	Name              string   `json:"name"`
	PlanCode          string   `json:"plan_code"`
	Description       string   `json:"description"`
	Amount            int64    `json:"amount"`
	Interval          string   `json:"interval"`
	SendInvoices      bool     `json:"send_invoices"`
	SendSMS           bool     `json:"send_sms"`
	HostedPage        bool     `json:"hosted_page"`
	HostedPageURL     string   `json:"hosted_page_url"`
	HostedPageSummary string   `json:"hosted_page_summary"`
	Currency          string   `json:"currency"`
	InvoiceLimit      int      `json:"invoice_limit"`
	CreatedAt         Time     `json:"createdAt"`
	UpdatedAt         Time     `json:"updatedAt"`
	Metadata          Metadata `json:"metadata,omitempty"`
}

Plan is the Paystack subscription plan record.

type PlanCreateParams

type PlanCreateParams struct {
	Params
	Name         string  `json:"name"`
	Amount       int64   `json:"amount"`
	Interval     string  `json:"interval"`
	Description  *string `json:"description,omitempty"`
	SendInvoices *bool   `json:"send_invoices,omitempty"`
	SendSMS      *bool   `json:"send_sms,omitempty"`
	Currency     *string `json:"currency,omitempty"`
	InvoiceLimit *int    `json:"invoice_limit,omitempty"`
}

PlanCreateParams is POST /plan.

type PlanListParams

type PlanListParams struct {
	ListParams
	Status   *string `url:"status,omitempty"`
	Interval *string `url:"interval,omitempty"`
	Amount   *int64  `url:"amount,omitempty"`
}

PlanListParams is GET /plan.

type PlanService

type PlanService struct {
	// contains filtered or unexported fields
}

PlanService is the default Planner implementation.

func (*PlanService) Create

func (s *PlanService) Create(ctx context.Context, p *PlanCreateParams) (*Plan, error)

Create registers a new plan.

func (*PlanService) Fetch

func (s *PlanService) Fetch(ctx context.Context, idOrCode string) (*Plan, error)

Fetch returns a plan by id or code.

func (*PlanService) List

func (s *PlanService) List(ctx context.Context, p *PlanListParams) ([]Plan, Meta, error)

List returns a page of plans.

func (*PlanService) Update

func (s *PlanService) Update(ctx context.Context, idOrCode string, p *PlanUpdateParams) error

Update edits a plan. Paystack returns no Data body, so Update returns only an error.

type PlanUpdateParams

type PlanUpdateParams struct {
	Params
	Name         *string `json:"name,omitempty"`
	Amount       *int64  `json:"amount,omitempty"`
	Interval     *string `json:"interval,omitempty"`
	Description  *string `json:"description,omitempty"`
	SendInvoices *bool   `json:"send_invoices,omitempty"`
	SendSMS      *bool   `json:"send_sms,omitempty"`
	Currency     *string `json:"currency,omitempty"`
	InvoiceLimit *int    `json:"invoice_limit,omitempty"`
}

PlanUpdateParams is PUT /plan/:id_or_code.

type Planner

type Planner interface {
	Create(ctx context.Context, params *PlanCreateParams) (*Plan, error)
	Fetch(ctx context.Context, idOrCode string) (*Plan, error)
	List(ctx context.Context, params *PlanListParams) ([]Plan, Meta, error)
	Update(ctx context.Context, idOrCode string, params *PlanUpdateParams) error
}

Planner is the contract for /plan endpoints.

type Refund

type Refund struct {
	ID             int64    `json:"id"`
	Domain         string   `json:"domain"`
	Transaction    int64    `json:"transaction"`
	Dispute        int64    `json:"dispute"`
	Amount         int64    `json:"amount"`
	DeductedAmount int64    `json:"deducted_amount"`
	Currency       string   `json:"currency"`
	Channel        string   `json:"channel"`
	MerchantNote   string   `json:"merchant_note"`
	CustomerNote   string   `json:"customer_note"`
	Status         string   `json:"status"`
	RefundedAt     Time     `json:"refunded_at"`
	RefundedBy     string   `json:"refunded_by"`
	ExpectedAt     Time     `json:"expected_at"`
	CreatedAt      Time     `json:"createdAt"`
	UpdatedAt      Time     `json:"updatedAt"`
	Metadata       Metadata `json:"metadata,omitempty"`
}

Refund is the Paystack refund record.

type RefundCreateParams

type RefundCreateParams struct {
	Params
	Transaction  string  `json:"transaction"`
	Amount       *int64  `json:"amount,omitempty"`
	Currency     *string `json:"currency,omitempty"`
	CustomerNote *string `json:"customer_note,omitempty"`
	MerchantNote *string `json:"merchant_note,omitempty"`
}

RefundCreateParams is POST /refund.

type RefundListParams

type RefundListParams struct {
	ListParams
	Reference *string `url:"reference,omitempty"`
	Currency  *string `url:"currency,omitempty"`
}

RefundListParams is GET /refund.

type RefundService

type RefundService struct {
	// contains filtered or unexported fields
}

RefundService is the default Refunder implementation.

func (*RefundService) Create

Create issues a new refund against a transaction.

func (*RefundService) Fetch

func (s *RefundService) Fetch(ctx context.Context, id string) (*Refund, error)

Fetch returns a refund by id.

func (*RefundService) List

List returns a page of refunds.

type Refunder

type Refunder interface {
	Create(ctx context.Context, params *RefundCreateParams) (*Refund, error)
	Fetch(ctx context.Context, id string) (*Refund, error)
	List(ctx context.Context, params *RefundListParams) ([]Refund, Meta, error)
}

Refunder is the contract for /refund endpoints.

type Response

type Response[T any] struct {
	Status  bool   `json:"status"`
	Message string `json:"message"`
	Data    T      `json:"data"`
}

Response is the single-record envelope Paystack returns from non-list endpoints. Callers typically do not see this — the client unwraps Data into the caller-supplied struct.

type Subscriber

type Subscriber interface {
	Create(ctx context.Context, params *SubscriptionCreateParams) (*Subscription, error)
	Fetch(ctx context.Context, idOrCode string) (*Subscription, error)
	List(ctx context.Context, params *SubscriptionListParams) ([]Subscription, Meta, error)
	Enable(ctx context.Context, params *SubscriptionToggleParams) error
	Disable(ctx context.Context, params *SubscriptionToggleParams) error
	GenerateUpdateLink(ctx context.Context, code string) (*SubscriptionManageLink, error)
}

Subscriber is the contract for /subscription endpoints.

type Subscription

type Subscription struct {
	ID               int64          `json:"id"`
	Domain           string         `json:"domain"`
	Status           string         `json:"status"`
	SubscriptionCode string         `json:"subscription_code"`
	EmailToken       string         `json:"email_token"`
	Amount           int64          `json:"amount"`
	CronExpression   string         `json:"cron_expression"`
	NextPaymentDate  Time           `json:"next_payment_date"`
	OpenInvoice      string         `json:"open_invoice"`
	CreatedAt        Time           `json:"createdAt"`
	UpdatedAt        Time           `json:"updatedAt"`
	Customer         *CustomerLite  `json:"customer,omitempty"`
	Plan             *Plan          `json:"plan,omitempty"`
	Authorization    *Authorization `json:"authorization,omitempty"`
}

Subscription is the Paystack subscription record.

type SubscriptionCreateParams

type SubscriptionCreateParams struct {
	Params
	Customer      string  `json:"customer"`
	Plan          string  `json:"plan"`
	Authorization *string `json:"authorization,omitempty"`
	StartDate     *Time   `json:"start_date,omitempty"`
}

SubscriptionCreateParams is POST /subscription.

type SubscriptionListParams

type SubscriptionListParams struct {
	ListParams
	Customer *int64  `url:"customer,omitempty"`
	Plan     *int64  `url:"plan,omitempty"`
	Status   *string `url:"status,omitempty"`
}

SubscriptionListParams is GET /subscription.

type SubscriptionManageLink struct {
	Link string `json:"link"`
}

SubscriptionManageLink is the response of /subscription/:code/manage/link.

type SubscriptionService

type SubscriptionService struct {
	// contains filtered or unexported fields
}

SubscriptionService is the default Subscriber implementation.

func (*SubscriptionService) Create

Create initiates a new subscription.

func (*SubscriptionService) Disable

Disable halts further billing on an active subscription.

func (*SubscriptionService) Enable

Enable re-activates a previously-disabled subscription.

func (*SubscriptionService) Fetch

func (s *SubscriptionService) Fetch(ctx context.Context, idOrCode string) (*Subscription, error)

Fetch returns a subscription by id or subscription_code.

func (s *SubscriptionService) GenerateUpdateLink(ctx context.Context, code string) (*SubscriptionManageLink, error)

GenerateUpdateLink returns a hosted URL where the subscriber can update their payment method.

func (*SubscriptionService) List

List returns a page of subscriptions.

type SubscriptionToggleParams

type SubscriptionToggleParams struct {
	Params
	Code  string `json:"code"`
	Token string `json:"token"`
}

SubscriptionToggleParams is POST /subscription/enable and /disable.

type Time

type Time struct {
	time.Time
}

Time wraps time.Time so the SDK can accept every date layout the Paystack API emits. Layouts are tried in order; the first one that parses wins. An empty JSON string, literal "null", or a JSON null yields the zero Time.

func (Time) MarshalJSON

func (t Time) MarshalJSON() ([]byte, error)

MarshalJSON emits an RFC 3339 timestamp, or JSON null for the zero value.

func (*Time) UnmarshalJSON

func (t *Time) UnmarshalJSON(data []byte) error

UnmarshalJSON parses a timestamp from any layout Paystack emits.

type Transaction

type Transaction struct {
	ID              int64          `json:"id"`
	Domain          string         `json:"domain"`
	Status          string         `json:"status"`
	Reference       string         `json:"reference"`
	Amount          int64          `json:"amount"`
	Message         string         `json:"message"`
	GatewayResponse string         `json:"gateway_response"`
	PaidAt          Time           `json:"paid_at"`
	CreatedAt       Time           `json:"created_at"`
	Channel         string         `json:"channel"`
	Currency        string         `json:"currency"`
	IPAddress       string         `json:"ip_address"`
	Fees            int64          `json:"fees"`
	Metadata        Metadata       `json:"metadata,omitempty"`
	Customer        *CustomerLite  `json:"customer,omitempty"`
	Authorization   *Authorization `json:"authorization,omitempty"`
}

Transaction is the full Paystack transaction record.

type TransactionChargeAuthorizationParams

type TransactionChargeAuthorizationParams struct {
	Params
	Email             string   `json:"email"`
	Amount            int64    `json:"amount"`
	AuthorizationCode string   `json:"authorization_code"`
	Reference         *string  `json:"reference,omitempty"`
	Currency          *string  `json:"currency,omitempty"`
	Queue             *bool    `json:"queue,omitempty"`
	Channels          []string `json:"channels,omitempty"`
}

TransactionChargeAuthorizationParams is POST /transaction/charge_authorization.

type TransactionInitializeData

type TransactionInitializeData struct {
	AuthorizationURL string `json:"authorization_url"`
	AccessCode       string `json:"access_code"`
	Reference        string `json:"reference"`
}

TransactionInitializeData is the response Data body for an initialize call.

type TransactionInitializeParams

type TransactionInitializeParams struct {
	Params
	Email       string   `json:"email"`
	Amount      int64    `json:"amount"`
	Currency    *string  `json:"currency,omitempty"`
	Reference   *string  `json:"reference,omitempty"`
	CallbackURL *string  `json:"callback_url,omitempty"`
	Plan        *string  `json:"plan,omitempty"`
	Channels    []string `json:"channels,omitempty"`
	SplitCode   *string  `json:"split_code,omitempty"`
	Subaccount  *string  `json:"subaccount,omitempty"`
	Bearer      *string  `json:"bearer,omitempty"`
}

TransactionInitializeParams is the payload for POST /transaction/initialize.

type TransactionListParams

type TransactionListParams struct {
	ListParams
	Customer *int64  `url:"customer,omitempty"`
	Status   *string `url:"status,omitempty"`
	Amount   *int64  `url:"amount,omitempty"`
}

TransactionListParams is the query for GET /transaction.

type TransactionService

type TransactionService struct {
	// contains filtered or unexported fields
}

TransactionService is the default Transactor implementation.

func (*TransactionService) ChargeAuthorization

ChargeAuthorization charges a previously-saved authorization code.

func (*TransactionService) Fetch

func (s *TransactionService) Fetch(ctx context.Context, id int64) (*Transaction, error)

Fetch returns a single transaction by numeric id.

func (*TransactionService) Initialize

Initialize begins a transaction and returns a checkout URL.

func (*TransactionService) List

List returns a page of transactions. Meta is always populated.

func (*TransactionService) Totals

Totals returns aggregate totals over the merchant account.

func (*TransactionService) Verify

func (s *TransactionService) Verify(ctx context.Context, reference string) (*Transaction, error)

Verify confirms the status of a transaction by reference.

type TransactionTotals

type TransactionTotals struct {
	TotalTransactions     int64            `json:"total_transactions"`
	UniqueCustomers       int64            `json:"unique_customers"`
	TotalVolume           int64            `json:"total_volume"`
	TotalVolumeByCurrency []CurrencyVolume `json:"total_volume_by_currency"`
	PendingTransfers      int64            `json:"pending_transfers"`
}

TransactionTotals is the aggregate returned by /transaction/totals.

type TransactionTotalsParams

type TransactionTotalsParams struct {
	ListParams
}

TransactionTotalsParams is the query for GET /transaction/totals.

type Transactor

type Transactor interface {
	Initialize(ctx context.Context, params *TransactionInitializeParams) (*TransactionInitializeData, error)
	Verify(ctx context.Context, reference string) (*Transaction, error)
	List(ctx context.Context, params *TransactionListParams) ([]Transaction, Meta, error)
	Fetch(ctx context.Context, id int64) (*Transaction, error)
	ChargeAuthorization(ctx context.Context, params *TransactionChargeAuthorizationParams) (*Transaction, error)
	Totals(ctx context.Context, params *TransactionTotalsParams) (*TransactionTotals, error)
}

Transactor is the contract for /transaction endpoints.

type Transfer

type Transfer struct {
	ID            int64    `json:"id"`
	Domain        string   `json:"domain"`
	Amount        int64    `json:"amount"`
	Currency      string   `json:"currency"`
	Reference     string   `json:"reference"`
	Source        string   `json:"source"`
	Reason        string   `json:"reason"`
	Recipient     int64    `json:"recipient"`
	Status        string   `json:"status"`
	TransferCode  string   `json:"transfer_code"`
	CreatedAt     Time     `json:"createdAt"`
	UpdatedAt     Time     `json:"updatedAt"`
	FailureReason string   `json:"failure_reason"`
	Metadata      Metadata `json:"metadata,omitempty"`
}

Transfer is the Paystack transfer record.

type TransferFinalizeParams

type TransferFinalizeParams struct {
	Params
	TransferCode string `json:"transfer_code"`
	OTP          string `json:"otp"`
}

TransferFinalizeParams is POST /transfer/finalize_transfer.

type TransferInitiateParams

type TransferInitiateParams struct {
	Params
	Source    string  `json:"source"`
	Amount    int64   `json:"amount"`
	Recipient string  `json:"recipient"`
	Reason    *string `json:"reason,omitempty"`
	Currency  *string `json:"currency,omitempty"`
	Reference *string `json:"reference,omitempty"`
}

TransferInitiateParams is POST /transfer.

type TransferListParams

type TransferListParams struct {
	ListParams
	Customer  *int64  `url:"customer,omitempty"`
	Recipient *int64  `url:"recipient,omitempty"`
	Status    *string `url:"status,omitempty"`
}

TransferListParams is GET /transfer.

type TransferService

type TransferService struct {
	// contains filtered or unexported fields
}

TransferService is the default Transferor implementation.

func (*TransferService) Fetch

func (s *TransferService) Fetch(ctx context.Context, idOrCode string) (*Transfer, error)

Fetch returns a transfer by id or transfer_code.

func (*TransferService) Finalize

Finalize completes a two-step transfer by supplying the OTP.

func (*TransferService) Initiate

Initiate queues a transfer to a recipient. A live-mode account may require a subsequent Finalize call if OTP is enabled.

func (*TransferService) List

List returns a page of transfers.

func (*TransferService) Verify

func (s *TransferService) Verify(ctx context.Context, reference string) (*Transfer, error)

Verify returns a transfer by reference.

type Transferor

type Transferor interface {
	Initiate(ctx context.Context, params *TransferInitiateParams) (*Transfer, error)
	Finalize(ctx context.Context, params *TransferFinalizeParams) (*Transfer, error)
	Fetch(ctx context.Context, idOrCode string) (*Transfer, error)
	Verify(ctx context.Context, reference string) (*Transfer, error)
	List(ctx context.Context, params *TransferListParams) ([]Transfer, Meta, error)
}

Transferor is the contract for /transfer endpoints.

Directories

Path Synopsis
internal
testutil
Package testutil provides doubles and fixture helpers for the paystack-go test suite.
Package testutil provides doubles and fixture helpers for the paystack-go test suite.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL