gopay

package module
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 11 Imported by: 0

README

gopay

Go Reference Go Report Card Go Version CI GitHub tag codecov

A unified payment processing library for Go with support for Stripe, PayPal, and Razorpay.

Each provider is a separate Go module, so you only pull in the dependencies you need.

Installation

# Core library (interfaces, types, mock provider)
go get github.com/KARTIKrocks/gopay

# Install only the providers you need:
go get github.com/KARTIKrocks/gopay/stripe
go get github.com/KARTIKrocks/gopay/paypal
go get github.com/KARTIKrocks/gopay/razorpay

Features

  • Unified interface for multiple payment providers
  • Support for Stripe, PayPal, and Razorpay
  • Dependency isolation: each provider is a separate module
  • Payment creation with automatic/manual capture
  • Refund processing (full and partial)
  • Customer management
  • Payment method management
  • Setup intents (save a card for later off-session charges)
  • Subscriptions and recurring billing (plans + subscriptions)
  • Webhook verification with signature validation
  • Mock provider for testing
  • Builder pattern for requests
  • Thread-safe (safe for concurrent use)

Supported Providers

Provider Payments Refunds Customers Payment Methods Setup Intents Subscriptions Invoices Webhooks Listing
Stripe Yes Yes Yes Yes Yes Yes Yes Yes Yes
PayPal Yes Yes No No No No No Yes No
Razorpay Yes Yes Yes No No Yes Yes Yes Yes

PayPal's Orders API has no list endpoint, so listing calls return ErrUnsupported for the PayPal provider. Setup intents (save-card-without-charging) are currently implemented for Stripe only; PayPal returns ErrUnsupported.

Invoices are read-only (GetInvoice) and implemented for Stripe and Razorpay, surfacing the normalized status, amounts, and a customer-facing hosted URL (Stripe's hosted_invoice_url, Razorpay's short_url). PayPal has no invoice concept in its Orders API and returns ErrUnsupported.

Subscriptions (recurring billing) are supported by Stripe and Razorpay. Razorpay's model differs in a few ways callers must handle: a subscription requires a finite number of billing cycles (set SubscriptionRequest.TotalCount via WithTotalCount), and it activates only after the customer authorizes the mandate at the returned Subscription.AuthURL — until then its status is SubscriptionStatusIncomplete. Because Razorpay binds the customer (and payment method) during that authorization, the request's CustomerID and PaymentMethodID are not sent on create; the returned subscription's CustomerID is populated by Razorpay once authorization completes. Recurring-billing webhooks are normalized for both providers (subscription.chargedWebhookInvoicePaymentSucceeded, subscription.cancelledWebhookSubscriptionCanceled, etc.), with WebhookEvent.SubscriptionID set. Stripe ignores TotalCount and leaves AuthURL empty.

Quick Start

Stripe
import (
    payment "github.com/KARTIKrocks/gopay"
    "github.com/KARTIKrocks/gopay/stripe"
)

config := stripe.DefaultConfig().
    WithSecretKey("sk_test_...")

provider, err := stripe.NewProvider(config)
if err != nil {
    log.Fatal(err)
}

client, err := payment.NewClient(provider)
if err != nil {
    log.Fatal(err)
}

// Create a payment
p, err := client.CreatePayment(ctx, payment.NewPaymentRequest(payment.USD(1999)).
    WithDescription("Order #123").
    WithPaymentMethod("pm_card_visa"))
PayPal
import (
    payment "github.com/KARTIKrocks/gopay"
    "github.com/KARTIKrocks/gopay/paypal"
)

config := paypal.DefaultConfig().
    WithCredentials("client_id", "client_secret").
    WithSandbox(true)

provider, err := paypal.NewProvider(config)
if err != nil {
    log.Fatal(err)
}

client, err := payment.NewClient(provider)
if err != nil {
    log.Fatal(err)
}

p, err := client.CreatePayment(ctx, payment.NewPaymentRequest(payment.USD(2500)).
    WithDescription("Order #456"))
Razorpay
import (
    payment "github.com/KARTIKrocks/gopay"
    "github.com/KARTIKrocks/gopay/razorpay"
)

config := razorpay.DefaultConfig().
    WithCredentials("key_id", "key_secret")

provider, err := razorpay.NewProvider(config)
if err != nil {
    log.Fatal(err)
}

client, err := payment.NewClient(provider)
if err != nil {
    log.Fatal(err)
}

p, err := client.CreatePayment(ctx, payment.NewPaymentRequest(payment.INR(50000)).
    WithDescription("Order #789"))

Currency Helpers

payment.USD(1999)  // $19.99 in cents
payment.EUR(500)   // €5.00 in cents
payment.GBP(250)   // £2.50 in pence
payment.INR(10000) // ₹100.00 in paise

Refunds

// Full refund
refund, err := client.FullRefund(ctx, paymentID)

// Partial refund
refund, err := client.Refund(ctx, payment.NewRefundRequest(paymentID).
    WithAmount(payment.USD(500)).
    WithReason(payment.RefundReasonRequestedByCustomer))

Setup Intents (save a card without charging)

A setup intent tokenizes and stores a payment method for future off-session charges — the standard primitive behind subscriptions and one-click checkout. It is an optional capability (Stripe only at present; other providers return ErrUnsupported).

// Create a setup intent. Without a PaymentMethodID, hand si.ClientSecret to the
// frontend to collect and confirm the card.
si, err := client.CreateSetupIntent(ctx, payment.NewSetupIntentRequest().
    WithCustomer(customerID).
    WithUsage(payment.SetupIntentUsageOffSession))
if err != nil {
    log.Fatal(err)
}

// If you already hold a payment method, pass it to confirm immediately.
si, err = client.CreateSetupIntent(ctx, payment.NewSetupIntentRequest().
    WithCustomer(customerID).
    WithPaymentMethod(paymentMethodID))
if err != nil {
    log.Fatal(err)
}

if si.IsSucceeded() {
    // si.PaymentMethodID is now stored on the customer for later charges.
}

// Retrieve or cancel later.
si, err = client.GetSetupIntent(ctx, si.ID)
if err != nil {
    log.Fatal(err)
}
si, err = client.CancelSetupIntent(ctx, si.ID)
if err != nil {
    log.Fatal(err)
}

Subscriptions (recurring billing)

Create a recurring plan, then subscribe a customer to it. The subscription charges the customer's payment method each billing cycle. This is an optional capability (Stripe only at present; other providers return ErrUnsupported).

// Create a recurring plan (amount + interval). In Stripe this becomes a
// recurring Price; plan.ID is what you subscribe customers to.
plan, err := client.CreatePlan(ctx, payment.NewPlanRequest(payment.USD(1999), payment.BillingIntervalMonth).
    WithName("Pro").
    WithIntervalCount(1))
if err != nil {
    log.Fatal(err)
}

// Subscribe a customer, charging a saved payment method each cycle.
sub, err := client.CreateSubscription(ctx, payment.NewSubscriptionRequest(customerID, plan.ID).
    WithPaymentMethod(paymentMethodID).
    WithTrialDays(14))
if err != nil {
    log.Fatal(err)
}
if sub.IsActive() {
    // sub.CurrentPeriodEnd is the next charge date.
}

// Cancel at the end of the current period (keeps access until then)...
sub, err = client.CancelSubscription(ctx, sub.ID, &payment.CancelOptions{AtPeriodEnd: true})
// ...or immediately (nil opts).
sub, err = client.CancelSubscription(ctx, sub.ID, nil)

React to billing outcomes via normalized webhook events (WebhookInvoicePaymentSucceeded, WebhookInvoicePaymentFailed, WebhookSubscriptionCanceled, …) — see below.

Webhooks

All providers support webhook signature verification through a unified interface:

event, err := client.VerifyWebhook(ctx, payload, map[string]string{
    "Stripe-Signature": signatureHeader, // for Stripe
    // "X-Razorpay-Signature": sig,      // for Razorpay
    // "PAYPAL-TRANSMISSION-SIG": sig,    // for PayPal (+ other PAYPAL-* headers)
})
if err != nil {
    // signature verification failed
}

fmt.Println(event.Type)     // e.g., "payment_intent.succeeded"
fmt.Println(event.Provider) // e.g., "stripe"

The event is also provider-normalized, so you can act on it without parsing the raw provider payload. Switch on event.Kind and read the normalized identifiers and amount directly:

switch event.Kind {
case payment.WebhookPaymentSucceeded:
    // event.PaymentID and event.OrderID are populated; event.Amount may be nil.
    if event.Amount != nil {
        markPaid(event.PaymentID, event.Amount)
    }
case payment.WebhookPaymentFailed:
    markFailed(event.PaymentID)
case payment.WebhookRefundSucceeded:
    recordRefund(event.RefundID, event.PaymentID, event.Amount)
case payment.WebhookSetupSucceeded:
    // event.SetupIntentID is populated; the payment method is ready for reuse.
    activateSavedCard(event.SetupIntentID)
case payment.WebhookSetupFailed:
    notifySetupFailed(event.SetupIntentID)
case payment.WebhookInvoicePaymentSucceeded:
    // Recurring charge paid; event.SubscriptionID/InvoiceID and Amount are set.
    extendSubscription(event.SubscriptionID, event.Amount)
case payment.WebhookInvoicePaymentFailed:
    flagPastDue(event.SubscriptionID)
case payment.WebhookSubscriptionCanceled:
    revokeAccess(event.SubscriptionID)
case payment.WebhookUnknown:
    // not a normalized event; fall back to event.Type / event.Raw
}

event.Amount is in integer minor units (like everywhere else in the library) and is nil when the event carries no amount. Amounts are normalized across providers — PayPal's major-unit decimal strings (e.g. "10.00") are converted to minor units automatically. Unmapped events keep Kind == WebhookUnknown with Type and Raw intact.

Listing & Pagination

Providers that support it (Stripe, Razorpay) can list payments, refunds, and customers with cursor-based pagination. Pass an opaque NextCursor from one page back via WithCursor to fetch the next:

params := payment.NewListParams().WithLimit(50)
for {
    page, err := client.ListPayments(ctx, params)
    if err != nil {
        // errors.Is(err, payment.ErrUnsupported) if the provider can't list
        break
    }
    for _, p := range page.Items {
        process(p)
    }
    if !page.HasMore {
        break
    }
    params = params.WithCursor(page.NextCursor)
}

ListRefunds and ListCustomers follow the same shape. Limit defaults to DefaultListLimit (20) and may not exceed MaxListLimit (100). The cursor is provider-specific and must be treated as opaque (Stripe uses an object ID; Razorpay uses a skip offset) — always pass back the NextCursor you received.

Error Handling

All provider errors are mapped to sentinel errors for consistent handling:

p, err := client.CreatePayment(ctx, req)
if errors.Is(err, payment.ErrCardDeclined) {
    // handle declined card
} else if errors.Is(err, payment.ErrInsufficientFunds) {
    // handle insufficient funds
} else if errors.Is(err, payment.ErrInvalidAmount) {
    // handle invalid amount
}

Mock Provider for Testing

mock := payment.NewMockProvider()
client, _ := payment.NewClient(mock)

// Configure behavior
mock.WithAutoSucceed(true)
mock.WithCreateError(payment.ErrCardDeclined) // simulate failures

// Use client as normal in tests
p, err := client.CreatePayment(ctx, payment.NewPaymentRequest(payment.USD(1000)).
    WithPaymentMethod("pm_test"))

// Inspect state
payments := mock.Payments()
mock.Reset()

License

MIT

Documentation

Overview

Package gopay provides a unified interface for payment processing across multiple providers including Stripe, PayPal, and Razorpay.

Each provider lives in its own sub-module so that importing one provider does not pull in the dependencies of another. For example, using PayPal will not require the Stripe SDK.

Core Package

This package defines the shared interfaces (Provider, CustomerProvider, PaymentMethodProvider, WebhookProvider), request/response types, sentinel errors, and the Client that wraps any provider with validation and convenience methods.

client, err := gopay.NewClient(provider)
p, err := client.CreatePayment(ctx, gopay.NewPaymentRequest(gopay.USD(1999)))

Providers

Install only the providers you need:

go get github.com/KARTIKrocks/gopay/stripe
go get github.com/KARTIKrocks/gopay/paypal
go get github.com/KARTIKrocks/gopay/razorpay

Each provider package exports a Config, a Provider (which implements Provider and optionally CustomerProvider / PaymentMethodProvider / WebhookProvider), and a NewProvider constructor.

Testing

Use MockProvider for unit tests without hitting any external API:

mock := gopay.NewMockProvider()
mock.WithAutoSucceed(true)
client, err := gopay.NewClient(mock)

Webhooks

Use WebhookProvider.VerifyWebhook to verify and parse incoming webhook events. Each provider package also exports a ParseWebhook function that parses the payload without signature verification — this is useful for debugging or when verification is handled elsewhere (e.g. by a gateway), but should not be used in production without separate verification.

The returned WebhookEvent is provider-normalized: switch on its Kind (a WebhookEventKind such as WebhookPaymentSucceeded or WebhookRefundSucceeded) and read the normalized PaymentID, OrderID, RefundID, and Amount fields instead of parsing the provider-specific Raw payload. Amount is in integer minor units across all providers (nil when absent); unmapped events have Kind WebhookUnknown with Type and Raw preserved.

Error Handling

All provider-specific errors are mapped to sentinel errors defined in this package (e.g. ErrCardDeclined, ErrInsufficientFunds, ErrNotFound). Use errors.Is for matching:

if errors.Is(err, gopay.ErrCardDeclined) {
    // handle declined card
}

Index

Constants

View Source
const (
	DefaultListLimit = 20
	MaxListLimit     = 100
)

Default and maximum page sizes for list operations. When ListParams.Limit is zero or negative, DefaultListLimit is used; Limit may not exceed MaxListLimit.

Variables

View Source
var (
	ErrInvalidConfig          = errors.New("gopay: invalid configuration")
	ErrInvalidAmount          = errors.New("gopay: invalid amount")
	ErrInvalidCurrency        = errors.New("gopay: invalid currency")
	ErrInvalidCard            = errors.New("gopay: invalid card")
	ErrCardDeclined           = errors.New("gopay: card declined")
	ErrInsufficientFunds      = errors.New("gopay: insufficient funds")
	ErrExpiredCard            = errors.New("gopay: expired card")
	ErrPaymentFailed          = errors.New("gopay: payment failed")
	ErrRefundFailed           = errors.New("gopay: refund failed")
	ErrSetupFailed            = errors.New("gopay: setup failed")
	ErrSubscriptionFailed     = errors.New("gopay: subscription failed")
	ErrNotFound               = errors.New("gopay: not found")
	ErrAlreadyRefunded        = errors.New("gopay: already refunded")
	ErrAlreadyCaptured        = errors.New("gopay: already captured")
	ErrAuthenticationRequired = errors.New("gopay: authentication required")
	ErrProviderError          = errors.New("gopay: provider error")
	ErrUnsupported            = errors.New("gopay: operation not supported")
)

Sentinel errors for payment operations.

Functions

This section is empty.

Types

type Address

type Address struct {
	Line1      string
	Line2      string
	City       string
	State      string
	PostalCode string
	Country    string
}

Address represents a physical address.

type Amount

type Amount struct {
	// Value is the amount in the smallest currency unit (e.g., cents).
	Value int64

	// Currency is the three-letter ISO currency code.
	Currency string
}

Amount represents a monetary amount.

func EUR

func EUR(cents int64) *Amount

EUR creates a EUR amount (in cents).

func GBP

func GBP(pence int64) *Amount

GBP creates a GBP amount (in pence).

func INR

func INR(paise int64) *Amount

INR creates an INR amount (in paise).

func NewAmount

func NewAmount(value int64, currency string) *Amount

NewAmount creates a new amount.

func ParseMajorUnitAmount added in v0.2.0

func ParseMajorUnitAmount(value, currency string) (*Amount, bool)

ParseMajorUnitAmount converts a major-unit decimal amount string (e.g. "10.00") in the given currency into a normalized minor-unit Amount (e.g. 1000 for USD, 500 for "500" JPY). Fractional digits beyond the currency's minor unit are rounded half-up.

It returns (nil, false) if the currency is unknown or the string is not a valid decimal number, so callers can leave WebhookEvent.Amount nil rather than recording a wrong value. Providers that already report integer minor units (Stripe, Razorpay) should use NewAmount directly instead.

func USD

func USD(cents int64) *Amount

USD creates a USD amount (in cents).

func (*Amount) Validate

func (a *Amount) Validate() error

Validate validates the amount. Currency should already be uppercase (NewAmount normalizes it).

type BillingDetails

type BillingDetails struct {
	// Name is the billing name.
	Name string

	// Email is the billing email.
	Email string

	// Phone is the billing phone.
	Phone string

	// Address is the billing address.
	Address *Address
}

BillingDetails contains billing information.

type BillingInterval added in v0.5.0

type BillingInterval string

BillingInterval is the unit of a plan's recurring billing period.

const (
	BillingIntervalDay   BillingInterval = "day"
	BillingIntervalWeek  BillingInterval = "week"
	BillingIntervalMonth BillingInterval = "month"
	BillingIntervalYear  BillingInterval = "year"
)

Billing interval values.

func (BillingInterval) String added in v0.5.0

func (b BillingInterval) String() string

String returns the string representation.

type CancelOptions added in v0.5.0

type CancelOptions struct {
	// AtPeriodEnd cancels at the end of the current billing period instead of
	// immediately. The subscription stays active (and continues to bill nothing
	// further) until the period ends.
	AtPeriodEnd bool
}

CancelOptions controls how a subscription is canceled.

type CaptureMethod

type CaptureMethod string

CaptureMethod determines when funds are captured.

const (
	// CaptureAutomatic captures funds immediately.
	CaptureAutomatic CaptureMethod = "automatic"
	// CaptureManual requires a separate capture call.
	CaptureManual CaptureMethod = "manual"
)

func (CaptureMethod) String

func (c CaptureMethod) String() string

String returns the string representation.

type CardDetails

type CardDetails struct {
	// Brand is the card brand (visa, mastercard, etc.).
	Brand string

	// Last4 is the last 4 digits.
	Last4 string

	// ExpMonth is the expiration month.
	ExpMonth int

	// ExpYear is the expiration year.
	ExpYear int

	// Funding is the funding type (credit, debit, prepaid).
	Funding string

	// Country is the card's country.
	Country string
}

CardDetails contains card information.

type Client

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

Client is the main payment client.

func NewClient

func NewClient(provider Provider) (*Client, error)

NewClient creates a new payment client.

func (*Client) AttachPaymentMethod

func (c *Client) AttachPaymentMethod(ctx context.Context, customerID, paymentMethodID string) error

AttachPaymentMethod attaches a payment method to a customer (if supported).

func (*Client) CancelPayment

func (c *Client) CancelPayment(ctx context.Context, paymentID string) (*Payment, error)

CancelPayment cancels an authorized payment.

func (*Client) CancelSetupIntent added in v0.4.0

func (c *Client) CancelSetupIntent(ctx context.Context, setupIntentID string) (*SetupIntent, error)

CancelSetupIntent cancels a setup intent (if supported).

func (*Client) CancelSubscription added in v0.5.0

func (c *Client) CancelSubscription(ctx context.Context, subscriptionID string, opts *CancelOptions) (*Subscription, error)

CancelSubscription cancels a subscription, immediately or at period end (if supported). A nil opts cancels immediately.

func (*Client) CapturePayment

func (c *Client) CapturePayment(ctx context.Context, paymentID string, amount *Amount) (*Payment, error)

CapturePayment captures an authorized payment.

func (*Client) CreateCustomer

func (c *Client) CreateCustomer(ctx context.Context, req *CustomerRequest) (*Customer, error)

CreateCustomer creates a customer (if supported).

func (*Client) CreatePayment

func (c *Client) CreatePayment(ctx context.Context, req *PaymentRequest) (*Payment, error)

CreatePayment creates a new payment.

func (*Client) CreatePlan added in v0.5.0

func (c *Client) CreatePlan(ctx context.Context, req *PlanRequest) (*Plan, error)

CreatePlan creates a recurring plan (if supported).

func (*Client) CreateSetupIntent added in v0.4.0

func (c *Client) CreateSetupIntent(ctx context.Context, req *SetupIntentRequest) (*SetupIntent, error)

CreateSetupIntent sets up a payment method for future off-session charges without moving money (if supported).

func (*Client) CreateSubscription added in v0.5.0

func (c *Client) CreateSubscription(ctx context.Context, req *SubscriptionRequest) (*Subscription, error)

CreateSubscription subscribes a customer to a plan (if supported).

func (*Client) DeleteCustomer

func (c *Client) DeleteCustomer(ctx context.Context, customerID string) error

DeleteCustomer deletes a customer (if supported).

func (*Client) DetachPaymentMethod

func (c *Client) DetachPaymentMethod(ctx context.Context, paymentMethodID string) error

DetachPaymentMethod detaches a payment method from a customer (if supported).

func (*Client) FullRefund

func (c *Client) FullRefund(ctx context.Context, paymentID string) (*Refund, error)

FullRefund creates a full refund for a payment.

func (*Client) GetCustomer

func (c *Client) GetCustomer(ctx context.Context, customerID string) (*Customer, error)

GetCustomer retrieves a customer (if supported).

func (*Client) GetInvoice added in v0.8.0

func (c *Client) GetInvoice(ctx context.Context, invoiceID string) (*Invoice, error)

GetInvoice retrieves an invoice by ID (if supported).

func (*Client) GetPayment

func (c *Client) GetPayment(ctx context.Context, paymentID string) (*Payment, error)

GetPayment retrieves a payment.

func (*Client) GetPlan added in v0.5.0

func (c *Client) GetPlan(ctx context.Context, planID string) (*Plan, error)

GetPlan retrieves a plan (if supported).

func (*Client) GetRefund

func (c *Client) GetRefund(ctx context.Context, refundID string) (*Refund, error)

GetRefund retrieves a refund.

func (*Client) GetSetupIntent added in v0.4.0

func (c *Client) GetSetupIntent(ctx context.Context, setupIntentID string) (*SetupIntent, error)

GetSetupIntent retrieves a setup intent (if supported).

func (*Client) GetSubscription added in v0.5.0

func (c *Client) GetSubscription(ctx context.Context, subscriptionID string) (*Subscription, error)

GetSubscription retrieves a subscription (if supported).

func (*Client) ListCustomers added in v0.3.0

func (c *Client) ListCustomers(ctx context.Context, params *ListParams) (*List[*Customer], error)

ListCustomers lists customers with cursor-based pagination (if supported).

func (*Client) ListPaymentMethods

func (c *Client) ListPaymentMethods(ctx context.Context, customerID string) ([]*PaymentMethod, error)

ListPaymentMethods lists payment methods for a customer (if supported).

func (*Client) ListPayments added in v0.3.0

func (c *Client) ListPayments(ctx context.Context, params *ListParams) (*List[*Payment], error)

ListPayments lists payments with cursor-based pagination (if supported).

func (*Client) ListRefunds added in v0.3.0

func (c *Client) ListRefunds(ctx context.Context, params *ListParams) (*List[*Refund], error)

ListRefunds lists refunds with cursor-based pagination (if supported).

func (*Client) Provider

func (c *Client) Provider() Provider

Provider returns the underlying provider.

func (*Client) ProviderName

func (c *Client) ProviderName() string

ProviderName returns the provider name.

func (*Client) Refund

func (c *Client) Refund(ctx context.Context, req *RefundRequest) (*Refund, error)

Refund creates a refund.

func (*Client) UpdateCustomer

func (c *Client) UpdateCustomer(ctx context.Context, customerID string, req *CustomerRequest) (*Customer, error)

UpdateCustomer updates a customer (if supported).

func (*Client) VerifyWebhook

func (c *Client) VerifyWebhook(ctx context.Context, payload []byte, headers map[string]string) (*WebhookEvent, error)

VerifyWebhook verifies and parses a webhook event (if supported).

type Customer

type Customer struct {
	// ID is the customer ID.
	ID string

	// Email is the customer's email.
	Email string

	// Name is the customer's name.
	Name string

	// Phone is the customer's phone.
	Phone string

	// Description is the description.
	Description string

	// DefaultPaymentMethodID is the default payment method.
	DefaultPaymentMethodID string

	// Metadata holds additional data.
	Metadata map[string]string

	// CreatedAt is the creation timestamp.
	CreatedAt time.Time

	// Provider is the provider name.
	Provider string

	// Raw contains the raw provider response.
	Raw map[string]any
}

Customer represents a customer.

type CustomerProvider

type CustomerProvider interface {
	Provider

	// CreateCustomer creates a new customer.
	CreateCustomer(ctx context.Context, req *CustomerRequest) (*Customer, error)

	// GetCustomer retrieves a customer by ID.
	GetCustomer(ctx context.Context, customerID string) (*Customer, error)

	// UpdateCustomer updates a customer.
	UpdateCustomer(ctx context.Context, customerID string, req *CustomerRequest) (*Customer, error)

	// DeleteCustomer deletes a customer.
	DeleteCustomer(ctx context.Context, customerID string) error
}

CustomerProvider extends Provider with customer management.

type CustomerRequest

type CustomerRequest struct {
	// Email is the customer's email.
	Email string

	// Name is the customer's name.
	Name string

	// Phone is the customer's phone.
	Phone string

	// Description is an optional description.
	Description string

	// Metadata holds additional data.
	Metadata map[string]string
}

CustomerRequest represents a customer creation/update request.

func NewCustomerRequest

func NewCustomerRequest(email string) *CustomerRequest

NewCustomerRequest creates a new customer request.

func (*CustomerRequest) Validate

func (r *CustomerRequest) Validate() error

Validate validates the customer request.

func (*CustomerRequest) WithDescription

func (r *CustomerRequest) WithDescription(desc string) *CustomerRequest

WithDescription sets the description.

func (*CustomerRequest) WithMetadata

func (r *CustomerRequest) WithMetadata(key, value string) *CustomerRequest

WithMetadata adds metadata.

func (*CustomerRequest) WithName

func (r *CustomerRequest) WithName(name string) *CustomerRequest

WithName sets the name.

func (*CustomerRequest) WithPhone

func (r *CustomerRequest) WithPhone(phone string) *CustomerRequest

WithPhone sets the phone.

type Invoice added in v0.8.0

type Invoice struct {
	// ID is the invoice ID.
	ID string

	// Status is the normalized invoice status.
	Status InvoiceStatus

	// SubscriptionID is the subscription this invoice bills, when it originates
	// from recurring billing; empty otherwise.
	SubscriptionID string

	// CustomerID is the customer the invoice is addressed to, when available.
	CustomerID string

	// Number is the provider's human-readable invoice number, when assigned.
	Number string

	// Amount is the total amount due in minor units; nil when the provider does
	// not report it.
	Amount *Amount

	// AmountPaid is the amount already paid in minor units; nil when the provider
	// does not report it.
	AmountPaid *Amount

	// HostedInvoiceURL is a customer-facing URL where the invoice can be viewed
	// and paid (Stripe's hosted_invoice_url, Razorpay's short_url); empty when
	// the provider does not expose one.
	HostedInvoiceURL string

	// PDFURL is a link to a downloadable PDF of the invoice, when the provider
	// offers one (Stripe); empty otherwise.
	PDFURL string

	// CreatedAt is the creation timestamp.
	CreatedAt time.Time

	// DueDate is when payment is due; zero when the provider does not set one.
	DueDate time.Time

	// PaidAt is when the invoice was paid; zero when unpaid or not reported.
	PaidAt time.Time

	// Metadata holds additional data.
	Metadata map[string]string

	// Provider is the provider name.
	Provider string

	// Raw contains the raw provider response.
	Raw map[string]any
}

Invoice represents a billing document generated by a provider, typically for a recurring subscription charge.

func (*Invoice) IsPaid added in v0.8.0

func (i *Invoice) IsPaid() bool

IsPaid returns true if the invoice has been fully paid.

type InvoiceProvider added in v0.8.0

type InvoiceProvider interface {
	Provider

	// GetInvoice retrieves an invoice by ID.
	GetInvoice(ctx context.Context, invoiceID string) (*Invoice, error)
}

InvoiceProvider extends Provider with read access to invoices — the billing documents providers generate for recurring subscription charges.

It is an optional interface: providers implement it only when their API exposes invoices. The Client gates each method with a runtime type assertion and returns ErrUnsupported for providers that don't implement it. Invoices are most useful alongside SubscriptionProvider, where each recurring cycle produces an invoice carrying the charged amount and a customer-facing hosted URL. Creation, voiding, and payment of invoices are intentionally out of scope; this interface is read-only.

type InvoiceStatus added in v0.8.0

type InvoiceStatus string

InvoiceStatus represents the lifecycle status of an invoice, normalized across providers.

const (
	// InvoiceStatusDraft is an invoice that has not yet been finalized.
	InvoiceStatusDraft InvoiceStatus = "draft"
	// InvoiceStatusOpen is a finalized invoice awaiting payment.
	InvoiceStatusOpen InvoiceStatus = "open"
	// InvoiceStatusPaid is a fully paid invoice.
	InvoiceStatusPaid InvoiceStatus = "paid"
	// InvoiceStatusVoid is an invoice that was voided before payment.
	InvoiceStatusVoid InvoiceStatus = "void"
	// InvoiceStatusUncollectible is an invoice marked as unlikely to be paid.
	InvoiceStatusUncollectible InvoiceStatus = "uncollectible"
)

Invoice status values.

func (InvoiceStatus) String added in v0.8.0

func (s InvoiceStatus) String() string

String returns the string representation.

type List added in v0.3.0

type List[T any] struct {
	// Items are the results on this page.
	Items []T

	// HasMore reports whether additional pages are available.
	HasMore bool

	// NextCursor is the opaque cursor for the next page; empty when HasMore is
	// false.
	NextCursor string
}

List is a single page of results from a paginated list operation.

HasMore reports whether further pages exist; when true, NextCursor holds the opaque cursor to pass to the next request (via ListParams.WithCursor).

type ListParams added in v0.3.0

type ListParams struct {
	// Limit is the maximum number of items to return per page. When zero or
	// negative, the provider's default page size (DefaultListLimit) is used.
	Limit int

	// Cursor is an opaque pagination cursor returned as NextCursor by a previous
	// page. Empty starts from the first page.
	Cursor string
}

ListParams controls pagination for list operations.

Pagination is cursor-based: each List result carries an opaque NextCursor that is passed back via WithCursor to fetch the following page. The cursor is provider-specific and must be treated as opaque by callers.

func NewListParams added in v0.3.0

func NewListParams() *ListParams

NewListParams creates a new ListParams with default pagination.

func (*ListParams) EffectiveLimit added in v0.3.0

func (p *ListParams) EffectiveLimit() int

EffectiveLimit returns the page size to request, applying DefaultListLimit when Limit is unset (zero or negative). It is a helper for provider implementations.

func (*ListParams) Validate added in v0.3.0

func (p *ListParams) Validate() error

Validate validates the list parameters.

func (*ListParams) WithCursor added in v0.3.0

func (p *ListParams) WithCursor(cursor string) *ListParams

WithCursor sets the pagination cursor (the NextCursor from a previous page).

func (*ListParams) WithLimit added in v0.3.0

func (p *ListParams) WithLimit(limit int) *ListParams

WithLimit sets the maximum number of items per page.

type ListProvider added in v0.3.0

type ListProvider interface {
	Provider

	// ListPayments lists payments with cursor-based pagination.
	ListPayments(ctx context.Context, params *ListParams) (*List[*Payment], error)

	// ListRefunds lists refunds with cursor-based pagination.
	ListRefunds(ctx context.Context, params *ListParams) (*List[*Refund], error)

	// ListCustomers lists customers with cursor-based pagination.
	ListCustomers(ctx context.Context, params *ListParams) (*List[*Customer], error)
}

ListProvider extends Provider with listing and pagination capabilities.

It is an optional interface: providers implement it only when their API supports listing. The Client gates each method with a runtime type assertion and returns ErrUnsupported for providers that don't implement it.

All methods must handle a nil params: use ListParams.EffectiveLimit to derive a safe page size and treat an empty cursor as "start from the first page".

type MockProvider

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

MockProvider is a mock payment provider for testing.

func NewMockProvider

func NewMockProvider() *MockProvider

NewMockProvider creates a new mock provider.

func (*MockProvider) AddInvoice added in v0.8.0

func (p *MockProvider) AddInvoice(inv *Invoice) *MockProvider

AddInvoice seeds an invoice so GetInvoice can return it. It exists because the mock has no invoice-creation flow; tests use it to stage retrievable invoices.

func (*MockProvider) AttachPaymentMethod

func (p *MockProvider) AttachPaymentMethod(ctx context.Context, customerID, paymentMethodID string) error

AttachPaymentMethod attaches a payment method to a customer.

func (*MockProvider) CancelPayment

func (p *MockProvider) CancelPayment(ctx context.Context, paymentID string) (*Payment, error)

CancelPayment cancels a mock payment.

func (*MockProvider) CancelSetupIntent added in v0.4.0

func (p *MockProvider) CancelSetupIntent(_ context.Context, setupIntentID string) (*SetupIntent, error)

CancelSetupIntent cancels a mock setup intent.

func (*MockProvider) CancelSubscription added in v0.5.0

func (p *MockProvider) CancelSubscription(_ context.Context, subscriptionID string, opts *CancelOptions) (*Subscription, error)

CancelSubscription cancels a mock subscription, immediately or at period end.

func (*MockProvider) CapturePayment

func (p *MockProvider) CapturePayment(ctx context.Context, paymentID string, amount *Amount) (*Payment, error)

CapturePayment captures a mock payment.

func (*MockProvider) CreateCustomer

func (p *MockProvider) CreateCustomer(ctx context.Context, req *CustomerRequest) (*Customer, error)

CreateCustomer creates a mock customer.

func (*MockProvider) CreatePayment

func (p *MockProvider) CreatePayment(ctx context.Context, req *PaymentRequest) (*Payment, error)

CreatePayment creates a mock payment.

func (*MockProvider) CreatePlan added in v0.5.0

func (p *MockProvider) CreatePlan(_ context.Context, req *PlanRequest) (*Plan, error)

CreatePlan creates a mock plan.

func (*MockProvider) CreateSetupIntent added in v0.4.0

func (p *MockProvider) CreateSetupIntent(_ context.Context, req *SetupIntentRequest) (*SetupIntent, error)

CreateSetupIntent creates a mock setup intent. When a PaymentMethodID is supplied and auto-succeed is on, the intent is marked succeeded; otherwise it awaits confirmation.

func (*MockProvider) CreateSubscription added in v0.5.0

func (p *MockProvider) CreateSubscription(_ context.Context, req *SubscriptionRequest) (*Subscription, error)

CreateSubscription creates a mock subscription. The plan must exist. When auto-succeed is on the subscription is active (or trialing when TrialDays is set); otherwise it is incomplete.

func (*MockProvider) Customers

func (p *MockProvider) Customers() map[string]*Customer

Customers returns all customers.

func (*MockProvider) DeleteCustomer

func (p *MockProvider) DeleteCustomer(ctx context.Context, customerID string) error

DeleteCustomer deletes a mock customer.

func (*MockProvider) DetachPaymentMethod

func (p *MockProvider) DetachPaymentMethod(ctx context.Context, paymentMethodID string) error

DetachPaymentMethod detaches a payment method.

func (*MockProvider) GetCustomer

func (p *MockProvider) GetCustomer(ctx context.Context, customerID string) (*Customer, error)

GetCustomer retrieves a mock customer.

func (*MockProvider) GetInvoice added in v0.8.0

func (p *MockProvider) GetInvoice(_ context.Context, invoiceID string) (*Invoice, error)

GetInvoice retrieves a seeded mock invoice.

func (*MockProvider) GetPayment

func (p *MockProvider) GetPayment(ctx context.Context, paymentID string) (*Payment, error)

GetPayment retrieves a mock payment.

func (*MockProvider) GetPlan added in v0.5.0

func (p *MockProvider) GetPlan(_ context.Context, planID string) (*Plan, error)

GetPlan retrieves a mock plan.

func (*MockProvider) GetRefund

func (p *MockProvider) GetRefund(ctx context.Context, refundID string) (*Refund, error)

GetRefund retrieves a mock refund.

func (*MockProvider) GetSetupIntent added in v0.4.0

func (p *MockProvider) GetSetupIntent(_ context.Context, setupIntentID string) (*SetupIntent, error)

GetSetupIntent retrieves a mock setup intent.

func (*MockProvider) GetSubscription added in v0.5.0

func (p *MockProvider) GetSubscription(_ context.Context, subscriptionID string) (*Subscription, error)

GetSubscription retrieves a mock subscription.

func (*MockProvider) ListCustomers added in v0.3.0

func (p *MockProvider) ListCustomers(_ context.Context, params *ListParams) (*List[*Customer], error)

ListCustomers lists mock customers with cursor-based pagination.

func (*MockProvider) ListPaymentMethods

func (p *MockProvider) ListPaymentMethods(ctx context.Context, customerID string) ([]*PaymentMethod, error)

ListPaymentMethods lists payment methods for a customer.

func (*MockProvider) ListPayments added in v0.3.0

func (p *MockProvider) ListPayments(_ context.Context, params *ListParams) (*List[*Payment], error)

ListPayments lists mock payments with cursor-based pagination. Results are ordered newest-first (by CreatedAt, then ID for determinism); the opaque cursor is the ID of the last item on the previous page.

func (*MockProvider) ListRefunds added in v0.3.0

func (p *MockProvider) ListRefunds(_ context.Context, params *ListParams) (*List[*Refund], error)

ListRefunds lists mock refunds with cursor-based pagination.

func (*MockProvider) Name

func (p *MockProvider) Name() string

Name returns the provider name.

func (*MockProvider) Payments

func (p *MockProvider) Payments() map[string]*Payment

Payments returns all payments.

func (*MockProvider) Refund

func (p *MockProvider) Refund(ctx context.Context, req *RefundRequest) (*Refund, error)

Refund creates a mock refund.

func (*MockProvider) Refunds

func (p *MockProvider) Refunds() map[string]*Refund

Refunds returns all refunds.

func (*MockProvider) Reset

func (p *MockProvider) Reset()

Reset clears all data.

func (*MockProvider) SetCustomer

func (p *MockProvider) SetCustomer(customer *Customer)

SetCustomer manually sets a customer.

func (*MockProvider) SetPayment

func (p *MockProvider) SetPayment(payment *Payment)

SetPayment manually sets a payment.

func (*MockProvider) SetPlan added in v0.5.0

func (p *MockProvider) SetPlan(plan *Plan)

SetPlan manually sets a plan.

func (*MockProvider) SetRefund

func (p *MockProvider) SetRefund(refund *Refund)

SetRefund manually sets a refund.

func (*MockProvider) SetSetupIntent added in v0.4.0

func (p *MockProvider) SetSetupIntent(si *SetupIntent)

SetSetupIntent manually sets a setup intent.

func (*MockProvider) SetSubscription added in v0.5.0

func (p *MockProvider) SetSubscription(sub *Subscription)

SetSubscription manually sets a subscription.

func (*MockProvider) UpdateCustomer

func (p *MockProvider) UpdateCustomer(ctx context.Context, customerID string, req *CustomerRequest) (*Customer, error)

UpdateCustomer updates a mock customer.

func (*MockProvider) VerifyWebhook

func (p *MockProvider) VerifyWebhook(_ context.Context, payload []byte, _ map[string]string) (*WebhookEvent, error)

VerifyWebhook verifies and parses a mock webhook event. It simply parses the payload as JSON and returns it as a WebhookEvent. Use WithWebhookError to simulate verification failures.

func (*MockProvider) WithAutoCapture

func (p *MockProvider) WithAutoCapture(auto bool) *MockProvider

WithAutoCapture sets whether payments are auto-captured.

func (*MockProvider) WithAutoSucceed

func (p *MockProvider) WithAutoSucceed(auto bool) *MockProvider

WithAutoSucceed sets whether payments auto-succeed.

func (*MockProvider) WithCaptureError

func (p *MockProvider) WithCaptureError(err error) *MockProvider

WithCaptureError sets the error to return on CapturePayment.

func (*MockProvider) WithCreateError

func (p *MockProvider) WithCreateError(err error) *MockProvider

WithCreateError sets the error to return on CreatePayment.

func (*MockProvider) WithRefundError

func (p *MockProvider) WithRefundError(err error) *MockProvider

WithRefundError sets the error to return on Refund.

func (*MockProvider) WithSetupError added in v0.4.0

func (p *MockProvider) WithSetupError(err error) *MockProvider

WithSetupError sets the error to return on CreateSetupIntent.

func (*MockProvider) WithSubscriptionError added in v0.5.0

func (p *MockProvider) WithSubscriptionError(err error) *MockProvider

WithSubscriptionError sets the error to return on CreatePlan and CreateSubscription.

func (*MockProvider) WithWebhookError

func (p *MockProvider) WithWebhookError(err error) *MockProvider

WithWebhookError sets the error to return on VerifyWebhook.

type Payment

type Payment struct {
	// ID is the payment ID.
	ID string

	// Amount is the payment amount.
	Amount *Amount

	// Status is the payment status.
	Status PaymentStatus

	// Description is the payment description.
	Description string

	// CustomerID is the associated customer ID.
	CustomerID string

	// PaymentMethodID is the payment method used.
	PaymentMethodID string

	// CaptureMethod is the capture method.
	CaptureMethod CaptureMethod

	// AmountCaptured is the amount captured.
	AmountCaptured int64

	// AmountRefunded is the amount refunded.
	AmountRefunded int64

	// FailureCode is the failure code if failed.
	FailureCode string

	// FailureMessage is the failure message if failed.
	FailureMessage string

	// ClientSecret is the client secret (for frontend).
	ClientSecret string

	// RedirectURL is the URL for 3DS redirect.
	RedirectURL string

	// Metadata holds additional data.
	Metadata map[string]string

	// CreatedAt is the creation timestamp.
	CreatedAt time.Time

	// Provider is the provider name.
	Provider string

	// Raw contains the raw provider response.
	Raw map[string]any
}

Payment represents a payment.

func (*Payment) IsCaptured

func (p *Payment) IsCaptured() bool

IsCaptured returns true if the payment was captured.

func (*Payment) IsSuccessful

func (p *Payment) IsSuccessful() bool

IsSuccessful returns true if the payment was successful.

func (*Payment) RequiresAction

func (p *Payment) RequiresAction() bool

RequiresAction returns true if the payment requires additional action.

type PaymentMethod

type PaymentMethod struct {
	// ID is the payment method ID.
	ID string

	// Type is the payment method type.
	Type PaymentMethodType

	// CustomerID is the associated customer ID.
	CustomerID string

	// Card contains card details (if type is card).
	Card *CardDetails

	// BillingDetails contains billing information.
	BillingDetails *BillingDetails

	// CreatedAt is the creation timestamp.
	CreatedAt time.Time

	// Provider is the provider name.
	Provider string

	// Raw contains the raw provider response.
	Raw map[string]any
}

PaymentMethod represents a payment method.

type PaymentMethodProvider

type PaymentMethodProvider interface {
	Provider

	// AttachPaymentMethod attaches a payment method to a customer.
	AttachPaymentMethod(ctx context.Context, customerID, paymentMethodID string) error

	// DetachPaymentMethod detaches a payment method from a customer.
	DetachPaymentMethod(ctx context.Context, paymentMethodID string) error

	// ListPaymentMethods lists payment methods for a customer.
	ListPaymentMethods(ctx context.Context, customerID string) ([]*PaymentMethod, error)
}

PaymentMethodProvider extends Provider with payment method management.

type PaymentMethodType

type PaymentMethodType string

PaymentMethodType represents the type of payment method.

const (
	PaymentMethodCard        PaymentMethodType = "card"
	PaymentMethodBankAccount PaymentMethodType = "bank_account"
	PaymentMethodWallet      PaymentMethodType = "wallet"
	PaymentMethodUPI         PaymentMethodType = "upi"
	PaymentMethodNetBanking  PaymentMethodType = "netbanking"
)

Payment method type values.

func (PaymentMethodType) String

func (t PaymentMethodType) String() string

String returns the string representation.

type PaymentRequest

type PaymentRequest struct {
	// Amount is the payment amount.
	Amount *Amount

	// Description is an optional description.
	Description string

	// CustomerID is the customer ID (optional).
	CustomerID string

	// PaymentMethodID is the payment method ID (optional).
	PaymentMethodID string

	// ReturnURL is the URL to redirect after payment (for 3DS).
	ReturnURL string

	// CaptureMethod determines when to capture funds.
	CaptureMethod CaptureMethod

	// Metadata holds additional data.
	Metadata map[string]string

	// IdempotencyKey for idempotent requests.
	IdempotencyKey string
}

PaymentRequest represents a payment creation request.

func NewPaymentRequest

func NewPaymentRequest(amount *Amount) *PaymentRequest

NewPaymentRequest creates a new payment request.

func (*PaymentRequest) Validate

func (r *PaymentRequest) Validate() error

Validate validates the payment request.

func (*PaymentRequest) WithCaptureMethod

func (r *PaymentRequest) WithCaptureMethod(method CaptureMethod) *PaymentRequest

WithCaptureMethod sets the capture method.

func (*PaymentRequest) WithCustomer

func (r *PaymentRequest) WithCustomer(customerID string) *PaymentRequest

WithCustomer sets the customer ID.

func (*PaymentRequest) WithDescription

func (r *PaymentRequest) WithDescription(desc string) *PaymentRequest

WithDescription sets the description.

func (*PaymentRequest) WithIdempotencyKey

func (r *PaymentRequest) WithIdempotencyKey(key string) *PaymentRequest

WithIdempotencyKey sets the idempotency key.

func (*PaymentRequest) WithMetadata

func (r *PaymentRequest) WithMetadata(key, value string) *PaymentRequest

WithMetadata adds metadata.

func (*PaymentRequest) WithPaymentMethod

func (r *PaymentRequest) WithPaymentMethod(paymentMethodID string) *PaymentRequest

WithPaymentMethod sets the payment method ID.

func (*PaymentRequest) WithReturnURL

func (r *PaymentRequest) WithReturnURL(url string) *PaymentRequest

WithReturnURL sets the return URL.

type PaymentStatus

type PaymentStatus string

PaymentStatus represents the status of a payment.

const (
	PaymentStatusPending         PaymentStatus = "pending"
	PaymentStatusRequiresAction  PaymentStatus = "requires_action"
	PaymentStatusProcessing      PaymentStatus = "processing"
	PaymentStatusSucceeded       PaymentStatus = "succeeded"
	PaymentStatusFailed          PaymentStatus = "failed"
	PaymentStatusCanceled        PaymentStatus = "canceled"
	PaymentStatusRequiresCapture PaymentStatus = "requires_capture"
)

Payment status values.

func (PaymentStatus) String

func (s PaymentStatus) String() string

String returns the string representation.

type Plan added in v0.5.0

type Plan struct {
	// ID is the plan ID.
	ID string

	// Name is the human-readable plan name.
	Name string

	// Amount is the recurring charge per interval.
	Amount *Amount

	// Interval is the billing interval unit.
	Interval BillingInterval

	// IntervalCount is the number of intervals between charges.
	IntervalCount int

	// Metadata holds additional data.
	Metadata map[string]string

	// CreatedAt is the creation timestamp.
	CreatedAt time.Time

	// Provider is the provider name.
	Provider string

	// Raw contains the raw provider response.
	Raw map[string]any
}

Plan represents a recurring price a customer can subscribe to.

type PlanRequest added in v0.5.0

type PlanRequest struct {
	// Amount is the recurring charge per interval.
	Amount *Amount

	// Interval is the billing interval unit (day/week/month/year).
	Interval BillingInterval

	// IntervalCount is the number of intervals between charges (e.g. Interval
	// month + IntervalCount 3 = quarterly). Defaults to 1.
	IntervalCount int

	// Name is a human-readable plan name.
	Name string

	// Metadata holds additional data.
	Metadata map[string]string

	// IdempotencyKey for idempotent requests.
	IdempotencyKey string
}

PlanRequest represents a plan-creation request.

func NewPlanRequest added in v0.5.0

func NewPlanRequest(amount *Amount, interval BillingInterval) *PlanRequest

NewPlanRequest creates a new plan request for the given amount and interval, defaulting IntervalCount to 1.

func (*PlanRequest) Validate added in v0.5.0

func (r *PlanRequest) Validate() error

Validate validates the plan request.

func (*PlanRequest) WithIdempotencyKey added in v0.5.0

func (r *PlanRequest) WithIdempotencyKey(key string) *PlanRequest

WithIdempotencyKey sets the idempotency key.

func (*PlanRequest) WithIntervalCount added in v0.5.0

func (r *PlanRequest) WithIntervalCount(count int) *PlanRequest

WithIntervalCount sets the number of intervals between charges.

func (*PlanRequest) WithMetadata added in v0.5.0

func (r *PlanRequest) WithMetadata(key, value string) *PlanRequest

WithMetadata adds metadata.

func (*PlanRequest) WithName added in v0.5.0

func (r *PlanRequest) WithName(name string) *PlanRequest

WithName sets the plan name.

type Provider

type Provider interface {
	// Name returns the provider name.
	Name() string

	// CreatePayment creates a new payment.
	CreatePayment(ctx context.Context, req *PaymentRequest) (*Payment, error)

	// GetPayment retrieves a payment by ID.
	GetPayment(ctx context.Context, paymentID string) (*Payment, error)

	// CapturePayment captures an authorized payment.
	CapturePayment(ctx context.Context, paymentID string, amount *Amount) (*Payment, error)

	// CancelPayment cancels an authorized payment.
	CancelPayment(ctx context.Context, paymentID string) (*Payment, error)

	// Refund creates a refund for a payment.
	Refund(ctx context.Context, req *RefundRequest) (*Refund, error)

	// GetRefund retrieves a refund by ID.
	GetRefund(ctx context.Context, refundID string) (*Refund, error)
}

Provider represents a payment provider.

type Refund

type Refund struct {
	// ID is the refund ID.
	ID string

	// PaymentID is the refunded payment ID.
	PaymentID string

	// Amount is the refund amount.
	Amount *Amount

	// Status is the refund status.
	Status RefundStatus

	// Reason is the refund reason.
	Reason RefundReason

	// FailureReason is the failure reason if failed.
	FailureReason string

	// Metadata holds additional data.
	Metadata map[string]string

	// CreatedAt is the creation timestamp.
	CreatedAt time.Time

	// Provider is the provider name.
	Provider string

	// Raw contains the raw provider response.
	Raw map[string]any
}

Refund represents a refund.

func (*Refund) IsSuccessful

func (r *Refund) IsSuccessful() bool

IsSuccessful returns true if the refund was successful.

type RefundReason

type RefundReason string

RefundReason represents the reason for a refund.

const (
	RefundReasonDuplicate           RefundReason = "duplicate"
	RefundReasonFraudulent          RefundReason = "fraudulent"
	RefundReasonRequestedByCustomer RefundReason = "requested_by_customer"
	RefundReasonOther               RefundReason = "other"
)

Refund reason values.

func (RefundReason) String

func (r RefundReason) String() string

String returns the string representation.

type RefundRequest

type RefundRequest struct {
	// PaymentID is the payment to refund.
	PaymentID string

	// Amount is the refund amount (nil for full refund).
	Amount *Amount

	// Reason is the refund reason.
	Reason RefundReason

	// Metadata holds additional data.
	Metadata map[string]string

	// IdempotencyKey for idempotent requests.
	IdempotencyKey string
}

RefundRequest represents a refund request.

func NewRefundRequest

func NewRefundRequest(paymentID string) *RefundRequest

NewRefundRequest creates a new refund request.

func (*RefundRequest) Validate

func (r *RefundRequest) Validate() error

Validate validates the refund request.

func (*RefundRequest) WithAmount

func (r *RefundRequest) WithAmount(amount *Amount) *RefundRequest

WithAmount sets the refund amount.

func (*RefundRequest) WithIdempotencyKey

func (r *RefundRequest) WithIdempotencyKey(key string) *RefundRequest

WithIdempotencyKey sets the idempotency key.

func (*RefundRequest) WithMetadata

func (r *RefundRequest) WithMetadata(key, value string) *RefundRequest

WithMetadata adds metadata.

func (*RefundRequest) WithReason

func (r *RefundRequest) WithReason(reason RefundReason) *RefundRequest

WithReason sets the refund reason.

type RefundStatus

type RefundStatus string

RefundStatus represents the status of a refund.

const (
	RefundStatusPending   RefundStatus = "pending"
	RefundStatusSucceeded RefundStatus = "succeeded"
	RefundStatusFailed    RefundStatus = "failed"
	RefundStatusCanceled  RefundStatus = "canceled"
)

Refund status values.

func (RefundStatus) String

func (s RefundStatus) String() string

String returns the string representation.

type SetupIntent added in v0.4.0

type SetupIntent struct {
	// ID is the setup intent ID.
	ID string

	// Status is the setup intent status.
	Status SetupIntentStatus

	// CustomerID is the associated customer ID.
	CustomerID string

	// PaymentMethodID is the payment method being set up (set once collected).
	PaymentMethodID string

	// Usage indicates how the stored method will be charged later.
	Usage SetupIntentUsage

	// Description is the setup intent description.
	Description string

	// ClientSecret is the client secret used to confirm the intent from a
	// frontend.
	ClientSecret string

	// RedirectURL is the URL for a 3DS / next-action redirect.
	RedirectURL string

	// FailureCode is the failure code if setup failed.
	FailureCode string

	// FailureMessage is the failure message if setup failed.
	FailureMessage string

	// Metadata holds additional data.
	Metadata map[string]string

	// CreatedAt is the creation timestamp.
	CreatedAt time.Time

	// Provider is the provider name.
	Provider string

	// Raw contains the raw provider response.
	Raw map[string]any
}

SetupIntent represents the setup of a payment method for future off-session charges.

func (*SetupIntent) IsSucceeded added in v0.4.0

func (s *SetupIntent) IsSucceeded() bool

IsSucceeded returns true if the payment method was successfully set up.

func (*SetupIntent) RequiresAction added in v0.4.0

func (s *SetupIntent) RequiresAction() bool

RequiresAction returns true if the setup intent requires additional action (e.g. 3DS authentication).

type SetupIntentProvider added in v0.4.0

type SetupIntentProvider interface {
	Provider

	// CreateSetupIntent creates a setup intent. When the request carries a
	// PaymentMethodID, the provider confirms it immediately (mirroring how
	// CreatePayment confirms an inline payment method); otherwise the intent is
	// returned awaiting client-side confirmation via its ClientSecret.
	CreateSetupIntent(ctx context.Context, req *SetupIntentRequest) (*SetupIntent, error)

	// GetSetupIntent retrieves a setup intent by ID.
	GetSetupIntent(ctx context.Context, setupIntentID string) (*SetupIntent, error)

	// CancelSetupIntent cancels a setup intent.
	CancelSetupIntent(ctx context.Context, setupIntentID string) (*SetupIntent, error)
}

SetupIntentProvider extends Provider with the ability to set up (tokenize and store) a payment method for future off-session charges without moving money.

It is an optional interface: providers implement it only when their API supports a save-card-without-charging flow. The Client gates each method with a runtime type assertion and returns ErrUnsupported for providers that don't implement it. SetupIntents are the standard primitive underpinning subscriptions and one-click checkout, where a stored mandate is charged later.

type SetupIntentRequest added in v0.4.0

type SetupIntentRequest struct {
	// CustomerID is the customer the payment method will be saved to. Optional,
	// but required by most providers for the stored method to be reusable
	// off-session.
	CustomerID string

	// PaymentMethodID is an existing payment method to attach and confirm
	// immediately. Optional; when empty the intent awaits client-side
	// confirmation via its ClientSecret.
	PaymentMethodID string

	// Usage indicates how the stored method will be charged later. Defaults to
	// SetupIntentUsageOffSession.
	Usage SetupIntentUsage

	// Description is an optional description.
	Description string

	// ReturnURL is the URL to redirect to after authentication (for 3DS).
	ReturnURL string

	// Metadata holds additional data.
	Metadata map[string]string

	// IdempotencyKey for idempotent requests.
	IdempotencyKey string
}

SetupIntentRequest represents a setup-intent creation request.

func NewSetupIntentRequest added in v0.4.0

func NewSetupIntentRequest() *SetupIntentRequest

NewSetupIntentRequest creates a new setup-intent request defaulting to off-session usage.

func (*SetupIntentRequest) Validate added in v0.4.0

func (r *SetupIntentRequest) Validate() error

Validate validates the setup-intent request.

func (*SetupIntentRequest) WithCustomer added in v0.4.0

func (r *SetupIntentRequest) WithCustomer(customerID string) *SetupIntentRequest

WithCustomer sets the customer ID.

func (*SetupIntentRequest) WithDescription added in v0.4.0

func (r *SetupIntentRequest) WithDescription(desc string) *SetupIntentRequest

WithDescription sets the description.

func (*SetupIntentRequest) WithIdempotencyKey added in v0.4.0

func (r *SetupIntentRequest) WithIdempotencyKey(key string) *SetupIntentRequest

WithIdempotencyKey sets the idempotency key.

func (*SetupIntentRequest) WithMetadata added in v0.4.0

func (r *SetupIntentRequest) WithMetadata(key, value string) *SetupIntentRequest

WithMetadata adds metadata.

func (*SetupIntentRequest) WithPaymentMethod added in v0.4.0

func (r *SetupIntentRequest) WithPaymentMethod(paymentMethodID string) *SetupIntentRequest

WithPaymentMethod sets the payment method ID to attach and confirm.

func (*SetupIntentRequest) WithReturnURL added in v0.4.0

func (r *SetupIntentRequest) WithReturnURL(url string) *SetupIntentRequest

WithReturnURL sets the return URL.

func (*SetupIntentRequest) WithUsage added in v0.4.0

WithUsage sets the intended usage.

type SetupIntentStatus added in v0.4.0

type SetupIntentStatus string

SetupIntentStatus represents the status of a setup intent.

const (
	SetupIntentStatusRequiresPaymentMethod SetupIntentStatus = "requires_payment_method"
	SetupIntentStatusRequiresConfirmation  SetupIntentStatus = "requires_confirmation"
	SetupIntentStatusRequiresAction        SetupIntentStatus = "requires_action"
	SetupIntentStatusProcessing            SetupIntentStatus = "processing"
	SetupIntentStatusSucceeded             SetupIntentStatus = "succeeded"
	SetupIntentStatusCanceled              SetupIntentStatus = "canceled"
)

Setup intent status values.

func (SetupIntentStatus) String added in v0.4.0

func (s SetupIntentStatus) String() string

String returns the string representation.

type SetupIntentUsage added in v0.4.0

type SetupIntentUsage string

SetupIntentUsage indicates how the stored payment method is intended to be charged later.

const (
	// SetupIntentUsageOffSession sets up a payment method to be charged when the
	// customer is not present (e.g. recurring subscription billing). This is the
	// default.
	SetupIntentUsageOffSession SetupIntentUsage = "off_session"
	// SetupIntentUsageOnSession sets up a payment method to be charged while the
	// customer is present (e.g. one-click checkout).
	SetupIntentUsageOnSession SetupIntentUsage = "on_session"
)

func (SetupIntentUsage) String added in v0.4.0

func (u SetupIntentUsage) String() string

String returns the string representation.

type Subscription added in v0.5.0

type Subscription struct {
	// ID is the subscription ID.
	ID string

	// CustomerID is the subscribed customer.
	CustomerID string

	// PlanID is the plan being billed.
	PlanID string

	// PaymentMethodID is the payment method charged each cycle.
	PaymentMethodID string

	// Status is the subscription status.
	Status SubscriptionStatus

	// CurrentPeriodStart is the start of the current billing period.
	CurrentPeriodStart time.Time

	// CurrentPeriodEnd is the end of the current billing period (next charge).
	CurrentPeriodEnd time.Time

	// CancelAtPeriodEnd reports whether the subscription is set to cancel at the
	// end of the current period.
	CancelAtPeriodEnd bool

	// CanceledAt is when the subscription was canceled; zero if not canceled.
	CanceledAt time.Time

	// AuthURL is a customer-facing URL the customer must visit to authorize the
	// recurring mandate before billing begins. It is set only by providers whose
	// subscriptions activate through a redirect/mandate flow (Razorpay); it is
	// empty for providers that charge a pre-authorized payment method (Stripe).
	AuthURL string

	// Metadata holds additional data.
	Metadata map[string]string

	// CreatedAt is the creation timestamp.
	CreatedAt time.Time

	// Provider is the provider name.
	Provider string

	// Raw contains the raw provider response.
	Raw map[string]any
}

Subscription represents a recurring billing arrangement between a customer and a plan.

func (*Subscription) IsActive added in v0.5.0

func (s *Subscription) IsActive() bool

IsActive returns true if the subscription is active or in a trial period.

type SubscriptionProvider added in v0.5.0

type SubscriptionProvider interface {
	Provider

	// CreatePlan creates a recurring plan (amount + interval).
	CreatePlan(ctx context.Context, req *PlanRequest) (*Plan, error)

	// GetPlan retrieves a plan by ID.
	GetPlan(ctx context.Context, planID string) (*Plan, error)

	// CreateSubscription subscribes a customer to a plan, charging their payment
	// method each billing cycle.
	CreateSubscription(ctx context.Context, req *SubscriptionRequest) (*Subscription, error)

	// GetSubscription retrieves a subscription by ID.
	GetSubscription(ctx context.Context, subscriptionID string) (*Subscription, error)

	// CancelSubscription cancels a subscription, either immediately or at the end
	// of the current billing period (see CancelOptions). A nil opts cancels
	// immediately.
	CancelSubscription(ctx context.Context, subscriptionID string, opts *CancelOptions) (*Subscription, error)
}

SubscriptionProvider extends Provider with recurring-billing capabilities: plans (recurring prices) and subscriptions that charge a customer's stored payment method each billing cycle.

It is an optional interface: providers implement it only when their API supports subscriptions. The Client gates each method with a runtime type assertion and returns ErrUnsupported for providers that don't implement it. Subscriptions charge a saved off-session payment method, so they build on the setup-intent flow (see SetupIntentProvider).

type SubscriptionRequest added in v0.5.0

type SubscriptionRequest struct {
	// CustomerID is the customer to subscribe. Whether it is required is
	// provider-dependent: providers that charge a stored payment method (Stripe)
	// require it, while providers that create the customer during a
	// customer-facing mandate-authorization redirect (Razorpay) ignore it. Each
	// provider enforces its own requirement; core validation does not.
	CustomerID string

	// PlanID is the plan to subscribe the customer to.
	PlanID string

	// PaymentMethodID is the payment method to charge each cycle. Optional when
	// the customer already has a default payment method. Providers that collect
	// the mandate through a customer-facing authorization redirect (Razorpay)
	// ignore it; see Subscription.AuthURL.
	PaymentMethodID string

	// TrialDays is the number of trial days before the first charge. Zero means
	// no trial.
	TrialDays int

	// TotalCount is the total number of billing cycles to run before the
	// subscription completes. Zero means "no fixed limit": providers that bill
	// open-ended (Stripe) ignore it, while providers that require a finite cycle
	// count (Razorpay) reject a zero value. Set it via WithTotalCount.
	TotalCount int

	// Metadata holds additional data.
	Metadata map[string]string

	// IdempotencyKey for idempotent requests.
	IdempotencyKey string
}

SubscriptionRequest represents a subscription-creation request.

func NewSubscriptionRequest added in v0.5.0

func NewSubscriptionRequest(customerID, planID string) *SubscriptionRequest

NewSubscriptionRequest creates a new subscription request for the given customer and plan.

func (*SubscriptionRequest) Validate added in v0.5.0

func (r *SubscriptionRequest) Validate() error

Validate validates the subscription request.

func (*SubscriptionRequest) WithIdempotencyKey added in v0.5.0

func (r *SubscriptionRequest) WithIdempotencyKey(key string) *SubscriptionRequest

WithIdempotencyKey sets the idempotency key.

func (*SubscriptionRequest) WithMetadata added in v0.5.0

func (r *SubscriptionRequest) WithMetadata(key, value string) *SubscriptionRequest

WithMetadata adds metadata.

func (*SubscriptionRequest) WithPaymentMethod added in v0.5.0

func (r *SubscriptionRequest) WithPaymentMethod(paymentMethodID string) *SubscriptionRequest

WithPaymentMethod sets the payment method to charge each cycle.

func (*SubscriptionRequest) WithTotalCount added in v0.6.0

func (r *SubscriptionRequest) WithTotalCount(count int) *SubscriptionRequest

WithTotalCount sets the total number of billing cycles before the subscription completes. Required by providers that only support finite subscriptions (Razorpay); ignored by open-ended providers (Stripe).

func (*SubscriptionRequest) WithTrialDays added in v0.5.0

func (r *SubscriptionRequest) WithTrialDays(days int) *SubscriptionRequest

WithTrialDays sets the number of trial days before the first charge.

type SubscriptionStatus added in v0.5.0

type SubscriptionStatus string

SubscriptionStatus represents the status of a subscription.

const (
	SubscriptionStatusActive            SubscriptionStatus = "active"
	SubscriptionStatusTrialing          SubscriptionStatus = "trialing"
	SubscriptionStatusPastDue           SubscriptionStatus = "past_due"
	SubscriptionStatusCanceled          SubscriptionStatus = "canceled"
	SubscriptionStatusIncomplete        SubscriptionStatus = "incomplete"
	SubscriptionStatusIncompleteExpired SubscriptionStatus = "incomplete_expired"
	SubscriptionStatusUnpaid            SubscriptionStatus = "unpaid"
	// SubscriptionStatusCompleted is set when a finite subscription has run all
	// of its billing cycles successfully (e.g. Razorpay's "completed"). It is a
	// terminal, non-failure state distinct from a cancellation.
	SubscriptionStatusCompleted SubscriptionStatus = "completed"
)

Subscription status values.

func (SubscriptionStatus) String added in v0.5.0

func (s SubscriptionStatus) String() string

String returns the string representation.

type WebhookEvent

type WebhookEvent struct {
	// ID is the event ID.
	ID string

	// Type is the raw provider event type, e.g. "payment_intent.succeeded".
	Type string

	// Provider is the provider name.
	Provider string

	// Raw contains the raw event payload.
	Raw []byte

	// Kind is the provider-normalized event category; WebhookUnknown for
	// events that don't map to a normalized category.
	Kind WebhookEventKind

	// PaymentID is the provider payment identifier, when the event concerns a
	// payment; empty otherwise.
	PaymentID string

	// OrderID is the provider order identifier, when present; empty otherwise.
	OrderID string

	// RefundID is the provider refund identifier, when the event concerns a
	// refund; empty otherwise.
	RefundID string

	// SetupIntentID is the provider setup-intent identifier, when the event
	// concerns a payment-method setup; empty otherwise.
	SetupIntentID string

	// SubscriptionID is the provider subscription identifier, when the event
	// concerns a subscription or recurring invoice; empty otherwise.
	SubscriptionID string

	// InvoiceID is the provider invoice identifier, when the event concerns a
	// recurring invoice; empty otherwise.
	InvoiceID string

	// Amount is the normalized amount in minor units; nil when the event
	// carries no amount or the amount could not be parsed.
	Amount *Amount
}

WebhookEvent represents a parsed webhook event.

In addition to the raw fields (Type, Raw), it carries provider-normalized fields (Kind, PaymentID, OrderID, RefundID, Amount) so callers can act on an event without hand-parsing the provider-specific Raw payload. Normalized fields are zero-valued ("" or nil) when they don't apply to the event.

type WebhookEventKind added in v0.2.0

type WebhookEventKind string

WebhookEventKind is a provider-normalized webhook event category. It lets callers switch on a unified set of event meanings regardless of provider, instead of parsing each provider's raw event-type string.

const (
	WebhookUnknown          WebhookEventKind = ""                  // unmapped/unsupported event
	WebhookPaymentCreated   WebhookEventKind = "payment.created"   // a payment was created/initiated
	WebhookPaymentSucceeded WebhookEventKind = "payment.succeeded" // payment captured/paid/completed
	WebhookPaymentFailed    WebhookEventKind = "payment.failed"    // payment attempt failed/denied
	WebhookPaymentCanceled  WebhookEventKind = "payment.canceled"  // payment canceled/voided
	WebhookRefundSucceeded  WebhookEventKind = "refund.succeeded"  // refund completed
	WebhookRefundFailed     WebhookEventKind = "refund.failed"     // refund failed
	WebhookSetupSucceeded   WebhookEventKind = "setup.succeeded"   // payment method setup completed
	WebhookSetupFailed      WebhookEventKind = "setup.failed"      // payment method setup failed

	WebhookSubscriptionCreated  WebhookEventKind = "subscription.created"  // subscription started
	WebhookSubscriptionUpdated  WebhookEventKind = "subscription.updated"  // subscription changed (plan/status)
	WebhookSubscriptionCanceled WebhookEventKind = "subscription.canceled" // subscription ended

	WebhookInvoicePaymentSucceeded WebhookEventKind = "invoice.payment_succeeded" // recurring charge paid
	WebhookInvoicePaymentFailed    WebhookEventKind = "invoice.payment_failed"    // recurring charge failed
)

Webhook event kinds. WebhookUnknown is used for events that don't map to a normalized category; callers can still inspect WebhookEvent.Type and Raw.

func (WebhookEventKind) String added in v0.2.0

func (k WebhookEventKind) String() string

String returns the string representation.

type WebhookProvider

type WebhookProvider interface {
	// VerifyWebhook verifies and parses a webhook event.
	// The headers map should contain the relevant signature headers from the HTTP request.
	VerifyWebhook(ctx context.Context, payload []byte, headers map[string]string) (*WebhookEvent, error)
}

WebhookProvider extends Provider with webhook verification.

Directories

Path Synopsis
razorpay module
stripe module

Jump to

Keyboard shortcuts

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