Documentation
¶
Overview ¶
Package nowpesa is the official Go SDK for the NowPesa payments API.
Quick start:
client := nowpesa.NewClient("key_id", "key_secret")
payment, err := client.Payments.Create(ctx, &nowpesa.CreatePaymentParams{
Reference: "order-1234",
Amount: 10000,
Currency: "KES",
Channel: nowpesa.ChannelMpesaSTKPush,
PayerPhone: "+254712345678",
})
All API methods return typed errors that wrap *Error. Branch with errors.As:
var rl *nowpesa.RateLimitError
if errors.As(err, &rl) {
time.Sleep(rl.RetryAfter)
}
The Client retries 429, 5xx, and network errors with exponential backoff. 4xx (other than 429) are surfaced immediately.
Index ¶
- func VerifyWebhook(body []byte, header, secret string, opts ...VerifyOptions) bool
- type APIError
- type AuthError
- type AuthResponse
- type AuthService
- type Channel
- type Client
- type ConflictError
- type CreatePaymentParams
- type CreatePayoutParams
- type ForbiddenError
- type ListDeliveriesParams
- type ListPaymentsParams
- type ListPaymentsResponse
- type ListPayoutsParams
- type ListPayoutsResponse
- type ListWebhookDeliveriesResponse
- type ListWebhooksResponse
- type LoginParams
- type NetworkError
- type NotFoundError
- type Option
- type Payment
- type PaymentStatus
- type PaymentsService
- func (s *PaymentsService) Create(ctx context.Context, params *CreatePaymentParams) (*Payment, error)
- func (s *PaymentsService) Get(ctx context.Context, id string) (*Payment, error)
- func (s *PaymentsService) List(ctx context.Context, params *ListPaymentsParams) (*ListPaymentsResponse, error)
- func (s *PaymentsService) Refund(ctx context.Context, paymentID string, params *RefundParams) (*Refund, error)
- type Payout
- type PayoutStatus
- type PayoutsService
- type PreconditionError
- type RateLimitError
- type Refund
- type RefundParams
- type RefundStatus
- type RegisterEndpointParams
- type RegisterParams
- type ServerError
- type Statement
- type StatementBucket
- type StatementParams
- type StatementService
- type ValidationError
- type VerifyOptions
- type WebhookDelivery
- type WebhookEndpoint
- type WebhookEvent
- type WebhooksService
- func (s *WebhooksService) Delete(ctx context.Context, id string) error
- func (s *WebhooksService) Get(ctx context.Context, id string) (*WebhookEndpoint, error)
- func (s *WebhooksService) List(ctx context.Context) (*ListWebhooksResponse, error)
- func (s *WebhooksService) ListDeliveries(ctx context.Context, endpointID string, params *ListDeliveriesParams) (*ListWebhookDeliveriesResponse, error)
- func (s *WebhooksService) PromoteSecret(ctx context.Context, id string) (*WebhookEndpoint, error)
- func (s *WebhooksService) Register(ctx context.Context, params *RegisterEndpointParams) (*WebhookEndpoint, error)
- func (s *WebhooksService) ReplayDelivery(ctx context.Context, endpointID, deliveryID string) error
- func (s *WebhooksService) RotateSecret(ctx context.Context, id string) (*WebhookEndpoint, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func VerifyWebhook ¶
func VerifyWebhook(body []byte, header, secret string, opts ...VerifyOptions) bool
VerifyWebhook returns true iff body + header are signed by secret and the t= timestamp is within tolerance. Constant-time compare.
Header format: "t=<unix_seconds>,v1=<hex_hmac_sha256>" — the signed payload is "<t>.<raw_body>".
Types ¶
type APIError ¶
type APIError struct {
StatusCode int // HTTP status; 0 when no response was received
Type string // `error.type` from the response envelope, or "network" / "unknown"
Message string // `error.message` from the envelope, or a synthesized fallback
Body string // Raw response body — useful for debugging
Path string // The endpoint that was called
RequestID string // X-Request-Id response header, if present
}
APIError is the base type returned from every Client method on non-2xx responses. Branch on the specific subtypes (e.g. *ValidationError, *RateLimitError) via errors.As — they all embed *APIError so its fields are promoted.
func AsAPIError ¶
AsAPIError unwraps any nowpesa typed error to its underlying *APIError. Returns false if err is not from this package.
type AuthResponse ¶
type AuthService ¶
type AuthService struct {
// contains filtered or unexported fields
}
AuthService exposes the public /v1/auth/{register,login} endpoints. These are unauthenticated; the merchant has no API key yet.
func (*AuthService) Login ¶
func (s *AuthService) Login(ctx context.Context, params *LoginParams) (*AuthResponse, error)
Login exchanges email + password for the merchant's API key.
func (*AuthService) Register ¶
func (s *AuthService) Register(ctx context.Context, params *RegisterParams) (*AuthResponse, error)
Register creates a new merchant + initial user + API key.
type Client ¶
type Client struct {
Auth *AuthService
Payments *PaymentsService
Payouts *PayoutsService
Webhooks *WebhooksService
Statement *StatementService
// contains filtered or unexported fields
}
Client is the entry point. Construct with NewClient and access resources via the exported service fields.
type ConflictError ¶
type ConflictError struct{ *APIError }
type CreatePaymentParams ¶
type CreatePaymentParams struct {
Reference string `json:"reference"`
Amount int64 `json:"amount"`
Currency string `json:"currency,omitempty"`
Channel Channel `json:"channel,omitempty"`
// PayerPhone is required for mpesa_stk_push. E.164 with leading "+".
PayerPhone string `json:"payer_phone,omitempty"`
// CardToken is required for card. Tokenized PAN reference.
CardToken string `json:"card_token,omitempty"`
// IdempotencyKey overrides the auto-generated UUIDv4. Use to dedup
// retries across processes.
IdempotencyKey string `json:"-"`
}
type CreatePayoutParams ¶
type CreatePayoutParams struct {
Amount int64 `json:"amount"`
Currency string `json:"currency,omitempty"`
// DestinationPhone is E.164 with leading "+". Overrides the
// merchant's default payout number when set.
DestinationPhone string `json:"destination_phone,omitempty"`
Remarks string `json:"remarks,omitempty"`
IdempotencyKey string `json:"-"`
}
type ForbiddenError ¶
type ForbiddenError struct{ *APIError }
type ListDeliveriesParams ¶
type ListPaymentsParams ¶
type ListPaymentsResponse ¶
type ListPayoutsParams ¶
type ListPayoutsParams struct {
Status PayoutStatus
Since string
Before string
Limit int
}
type ListPayoutsResponse ¶
type ListWebhookDeliveriesResponse ¶
type ListWebhookDeliveriesResponse struct {
Data []WebhookDelivery `json:"data"`
}
type ListWebhooksResponse ¶
type ListWebhooksResponse struct {
Data []WebhookEndpoint `json:"data"`
}
type LoginParams ¶
type NetworkError ¶
NetworkError wraps a transport-layer failure (DNS, connect, TLS, timeout, etc.) with no HTTP response. Unwrap returns the underlying transport error so errors.Is works.
func (*NetworkError) Error ¶
func (e *NetworkError) Error() string
func (*NetworkError) Unwrap ¶
func (e *NetworkError) Unwrap() error
type NotFoundError ¶
type NotFoundError struct{ *APIError }
type Option ¶
type Option func(*Client)
Option configures a Client. Pass to NewClient.
func WithBaseURL ¶
WithBaseURL overrides the API endpoint. Useful for staging or local dev.
func WithDefaultHeader ¶
WithDefaultHeader sets a header sent on every request. Per-request headers (passed via service methods) override these.
func WithHTTPClient ¶
WithHTTPClient injects a custom *http.Client. The default has a 30s timeout; supply your own for finer control (e.g. transport tracing).
func WithMaxRetries ¶
WithMaxRetries sets the number of retries for 429/5xx/network errors. Default 3. Zero disables retries.
func WithSleepFunc ¶
WithSleepFunc swaps the sleep implementation used between retries. Exposed primarily for testing the retry loop without real waits.
func WithUserAgent ¶
WithUserAgent overrides the User-Agent header.
type Payment ¶
type Payment struct {
ID string `json:"id"`
Reference string `json:"reference"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
Channel Channel `json:"channel"`
Status PaymentStatus `json:"status"`
Fee int64 `json:"fee,omitempty"`
NetAmount int64 `json:"net_amount,omitempty"`
FailureReason string `json:"failure_reason,omitempty"`
ChannelReceipt string `json:"channel_receipt,omitempty"`
RefundedAt *time.Time `json:"refunded_at,omitempty"`
Refund *Refund `json:"refund,omitempty"`
RefundedMinor int64 `json:"refunded_minor,omitempty"`
Refunds []Refund `json:"refunds,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
type PaymentStatus ¶
type PaymentStatus string
const ( PaymentPending PaymentStatus = "pending" PaymentProcessing PaymentStatus = "processing" PaymentSucceeded PaymentStatus = "succeeded" PaymentFailed PaymentStatus = "failed" PaymentCanceled PaymentStatus = "canceled" )
type PaymentsService ¶
type PaymentsService struct {
// contains filtered or unexported fields
}
func (*PaymentsService) Create ¶
func (s *PaymentsService) Create(ctx context.Context, params *CreatePaymentParams) (*Payment, error)
Create initiates a payment via the requested channel. Card payments resolve synchronously; mpesa_stk_push returns immediately with status processing and finalizes via webhook.
func (*PaymentsService) List ¶
func (s *PaymentsService) List(ctx context.Context, params *ListPaymentsParams) (*ListPaymentsResponse, error)
List returns a page of payments with cursor pagination. Carry the returned NextBefore back into the next call to walk forward.
func (*PaymentsService) Refund ¶
func (s *PaymentsService) Refund(ctx context.Context, paymentID string, params *RefundParams) (*Refund, error)
Refund issues a full or partial refund. Pass nil for a full refund of the remaining balance.
type Payout ¶
type Payout struct {
ID string `json:"id"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
Channel string `json:"channel"`
Status PayoutStatus `json:"status"`
DestinationPhone string `json:"destination_phone"`
ChannelReceipt string `json:"channel_receipt,omitempty"`
FailureReason string `json:"failure_reason,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
type PayoutStatus ¶
type PayoutStatus string
const ( PayoutPending PayoutStatus = "pending" PayoutSucceeded PayoutStatus = "succeeded" PayoutFailed PayoutStatus = "failed" )
type PayoutsService ¶
type PayoutsService struct {
// contains filtered or unexported fields
}
func (*PayoutsService) Create ¶
func (s *PayoutsService) Create(ctx context.Context, params *CreatePayoutParams) (*Payout, error)
func (*PayoutsService) List ¶
func (s *PayoutsService) List(ctx context.Context, params *ListPayoutsParams) (*ListPayoutsResponse, error)
type PreconditionError ¶
type PreconditionError struct{ *APIError }
type RateLimitError ¶
RateLimitError is returned on HTTP 429. RetryAfter mirrors the Retry-After header (0 if absent or unparseable).
type Refund ¶
type Refund struct {
ID string `json:"id"`
PaymentID string `json:"payment_id"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
Status RefundStatus `json:"status"`
FailureReason string `json:"failure_reason,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type RefundParams ¶
type RefundStatus ¶
type RefundStatus string
const ( RefundPending RefundStatus = "pending" RefundSucceeded RefundStatus = "succeeded" RefundFailed RefundStatus = "failed" )
type RegisterEndpointParams ¶
type RegisterParams ¶
type ServerError ¶
type ServerError struct{ *APIError }
type Statement ¶
type Statement struct {
MerchantID string `json:"merchant_id"`
Currency string `json:"currency"`
Since string `json:"since,omitempty"`
Before string `json:"before,omitempty"`
InboundSucceeded StatementBucket `json:"inbound_succeeded"`
FeesPaidMinor int64 `json:"fees_paid_minor"`
RefundsSucceeded StatementBucket `json:"refunds_succeeded"`
PayoutsSucceeded StatementBucket `json:"payouts_succeeded"`
PayoutsPending StatementBucket `json:"payouts_pending"`
AvailablePayableMinor int64 `json:"available_payable_minor"`
PayablePendingMinor int64 `json:"payable_pending_minor"`
}
type StatementBucket ¶
type StatementParams ¶
type StatementService ¶
type StatementService struct {
// contains filtered or unexported fields
}
func (*StatementService) DownloadCSV ¶
func (s *StatementService) DownloadCSV(ctx context.Context, params *StatementParams) (*http.Response, error)
DownloadCSV returns the raw *http.Response so the caller can stream the CSV body straight to disk or another HTTP response. Caller must close resp.Body when done.
resp, err := client.Statement.DownloadCSV(ctx, &nowpesa.StatementParams{...})
if err != nil { ... }
defer resp.Body.Close()
io.Copy(out, resp.Body)
func (*StatementService) Get ¶
func (s *StatementService) Get(ctx context.Context, params *StatementParams) (*Statement, error)
Get returns the merchant's statement as a structured snapshot.
type ValidationError ¶
type ValidationError struct{ *APIError }
type VerifyOptions ¶
type VerifyOptions struct {
// Tolerance for the timestamp drift, default 300s.
Tolerance time.Duration
// NextSecret is the rotated-in secret. When set together with
// NextHeader, VerifyWebhook returns true if EITHER signature
// verifies — used during the rotate → promote window.
NextSecret string
NextHeader string
// Now overrides the clock (testing). Defaults to time.Now.
Now func() time.Time
}
VerifyOptions tunes VerifyWebhook. Zero value uses sane defaults (300s tolerance, no rotation header).
type WebhookDelivery ¶
type WebhookDelivery struct {
ID string `json:"id"`
EndpointID string `json:"endpoint_id"`
EventID string `json:"event_id"`
EventType string `json:"event_type"`
Status string `json:"status"`
Attempts int32 `json:"attempts"`
LastStatusCode int32 `json:"last_status_code,omitempty"`
LastError string `json:"last_error,omitempty"`
LastAttemptAt *time.Time `json:"last_attempt_at,omitempty"`
NextAttemptAt *time.Time `json:"next_attempt_at,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
Payload json.RawMessage `json:"payload,omitempty"`
}
type WebhookEndpoint ¶
type WebhookEndpoint struct {
ID string `json:"id"`
URL string `json:"url"`
EventTypes []string `json:"event_types"`
CreatedAt time.Time `json:"created_at"`
SigningSecret string `json:"signing_secret,omitempty"`
SigningSecretNext string `json:"signing_secret_next,omitempty"`
SigningSecretRotatedAt *time.Time `json:"signing_secret_rotated_at,omitempty"`
}
type WebhookEvent ¶
type WebhookEvent struct {
ID string `json:"id"`
Type string `json:"type"`
MerchantID string `json:"merchant_id"`
CreatedAt time.Time `json:"created_at"`
Data json.RawMessage `json:"data"`
}
WebhookEvent is the canonical envelope NowPesa POSTs to your endpoint. Use json.Unmarshal on Data into a channel-specific payload after branching on Type.
func ParseEvent ¶
func ParseEvent(body []byte) (*WebhookEvent, error)
ParseEvent unmarshals the canonical webhook envelope from a raw body. Call after VerifyWebhook succeeds.
type WebhooksService ¶
type WebhooksService struct {
// contains filtered or unexported fields
}
func (*WebhooksService) Delete ¶
func (s *WebhooksService) Delete(ctx context.Context, id string) error
func (*WebhooksService) Get ¶
func (s *WebhooksService) Get(ctx context.Context, id string) (*WebhookEndpoint, error)
func (*WebhooksService) List ¶
func (s *WebhooksService) List(ctx context.Context) (*ListWebhooksResponse, error)
func (*WebhooksService) ListDeliveries ¶
func (s *WebhooksService) ListDeliveries(ctx context.Context, endpointID string, params *ListDeliveriesParams) (*ListWebhookDeliveriesResponse, error)
func (*WebhooksService) PromoteSecret ¶
func (s *WebhooksService) PromoteSecret(ctx context.Context, id string) (*WebhookEndpoint, error)
func (*WebhooksService) Register ¶
func (s *WebhooksService) Register(ctx context.Context, params *RegisterEndpointParams) (*WebhookEndpoint, error)
func (*WebhooksService) ReplayDelivery ¶
func (s *WebhooksService) ReplayDelivery(ctx context.Context, endpointID, deliveryID string) error
func (*WebhooksService) RotateSecret ¶
func (s *WebhooksService) RotateSecret(ctx context.Context, id string) (*WebhookEndpoint, error)