callbacks

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Dec 2, 2025 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrCallbackDisabled = errors.New("callbacks: disabled")

ErrCallbackDisabled is returned when callbacks are not configured.

Functions

func PreparePaymentEvent

func PreparePaymentEvent(event *PaymentEvent)

PreparePaymentEvent ensures PaymentEvent has required idempotency fields set. If EventID is already set, it's preserved (for retries). If not, a new one is generated.

func PrepareRefundEvent

func PrepareRefundEvent(event *RefundEvent)

PrepareRefundEvent ensures RefundEvent has required idempotency fields set. If EventID is already set, it's preserved (for retries). If not, a new one is generated.

func SendOnce

func SendOnce(ctx context.Context, cfg config.CallbacksConfig, event PaymentEvent) error

SendOnce sends a payment event webhook without retry logic (for testing/CLI tools).

Types

type DLQStore

type DLQStore interface {
	SaveFailedWebhook(ctx context.Context, webhook FailedWebhook) error
	ListFailedWebhooks(ctx context.Context, limit int) ([]FailedWebhook, error)
	DeleteFailedWebhook(ctx context.Context, id string) error
}

DLQStore persists failed webhook attempts for manual retry or analysis.

type FailedWebhook

type FailedWebhook struct {
	ID          string            `json:"id"`
	URL         string            `json:"url"`
	Payload     json.RawMessage   `json:"payload"`
	Headers     map[string]string `json:"headers"`
	EventType   string            `json:"eventType"` // "payment" or "refund"
	Attempts    int               `json:"attempts"`
	LastError   string            `json:"lastError"`
	LastAttempt time.Time         `json:"lastAttempt"`
	CreatedAt   time.Time         `json:"createdAt"`
}

FailedWebhook represents a webhook that exhausted all retry attempts.

type FileDLQStore

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

FileDLQStore stores failed webhooks in a JSON file.

func NewFileDLQStore

func NewFileDLQStore(filePath string) (*FileDLQStore, error)

NewFileDLQStore creates a file-based DLQ store.

func (*FileDLQStore) Close

func (f *FileDLQStore) Close() error

Close ensures all data is persisted (no-op for file store).

func (*FileDLQStore) DeleteFailedWebhook

func (f *FileDLQStore) DeleteFailedWebhook(ctx context.Context, id string) error

func (*FileDLQStore) ListFailedWebhooks

func (f *FileDLQStore) ListFailedWebhooks(ctx context.Context, limit int) ([]FailedWebhook, error)

func (*FileDLQStore) SaveFailedWebhook

func (f *FileDLQStore) SaveFailedWebhook(ctx context.Context, webhook FailedWebhook) error

type MemoryDLQStore

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

MemoryDLQStore stores failed webhooks in memory (for testing/development).

func NewMemoryDLQStore

func NewMemoryDLQStore() *MemoryDLQStore

NewMemoryDLQStore creates an in-memory DLQ store.

func (*MemoryDLQStore) DeleteFailedWebhook

func (m *MemoryDLQStore) DeleteFailedWebhook(ctx context.Context, id string) error

func (*MemoryDLQStore) ListFailedWebhooks

func (m *MemoryDLQStore) ListFailedWebhooks(ctx context.Context, limit int) ([]FailedWebhook, error)

func (*MemoryDLQStore) SaveFailedWebhook

func (m *MemoryDLQStore) SaveFailedWebhook(ctx context.Context, webhook FailedWebhook) error

type NoopDLQStore

type NoopDLQStore struct{}

NoopDLQStore is a DLQ store that discards all failed webhooks.

func (NoopDLQStore) DeleteFailedWebhook

func (NoopDLQStore) DeleteFailedWebhook(context.Context, string) error

func (NoopDLQStore) ListFailedWebhooks

func (NoopDLQStore) ListFailedWebhooks(context.Context, int) ([]FailedWebhook, error)

func (NoopDLQStore) SaveFailedWebhook

func (NoopDLQStore) SaveFailedWebhook(context.Context, FailedWebhook) error

type NoopNotifier

type NoopNotifier struct{}

NoopNotifier ignores all events.

func (NoopNotifier) PaymentSucceeded

func (NoopNotifier) PaymentSucceeded(context.Context, PaymentEvent)

func (NoopNotifier) RefundSucceeded

func (NoopNotifier) RefundSucceeded(context.Context, RefundEvent)

type Notifier

type Notifier interface {
	PaymentSucceeded(ctx context.Context, event PaymentEvent)
	RefundSucceeded(ctx context.Context, event RefundEvent)
}

Notifier delivers payment events to user-defined callbacks.

func NewRetryableClient

func NewRetryableClient(cfg config.CallbacksConfig, opts ...RetryOption) Notifier

NewRetryableClient constructs a callback client with retry support.

type PaymentEvent

type PaymentEvent struct {
	// Idempotency and event metadata (ALWAYS present)
	EventID        string    `json:"eventId"`        // Unique event identifier for idempotency (e.g., "evt_abc123")
	EventType      string    `json:"eventType"`      // Always "payment.succeeded" for this event
	EventTimestamp time.Time `json:"eventTimestamp"` // ISO8601 timestamp when event was created (UTC)

	// Payment details
	ResourceID         string            `json:"resource"`
	Method             string            `json:"method"` // "stripe" or "x402"
	StripeSessionID    string            `json:"stripeSessionId,omitempty"`
	StripeCustomer     string            `json:"stripeCustomer,omitempty"`
	FiatAmountCents    int64             `json:"fiatAmountCents,omitempty"`
	FiatCurrency       string            `json:"fiatCurrency,omitempty"`
	CryptoAtomicAmount int64             `json:"cryptoAtomicAmount,omitempty"`
	CryptoToken        string            `json:"cryptoToken,omitempty"`
	Wallet             string            `json:"wallet,omitempty"`
	ProofSignature     string            `json:"proofSignature,omitempty"`
	Metadata           map[string]string `json:"metadata,omitempty"`
	PaidAt             time.Time         `json:"paidAt"`
}

PaymentEvent encapsulates the essential information about a completed payment. IMPORTANT: EventID is the idempotency key - webhook consumers MUST use this to prevent duplicate processing.

type PersistentCallbackClient

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

PersistentCallbackClient delivers webhooks via a persistent queue. Unlike RetryableClient which uses goroutines (lost on restart), this client persists webhooks to the database for guaranteed delivery across server restarts.

func NewPersistentCallbackClient

func NewPersistentCallbackClient(opts PersistentCallbackOptions) *PersistentCallbackClient

NewPersistentCallbackClient creates a callback client with persistent queue backing.

func (*PersistentCallbackClient) Close

func (c *PersistentCallbackClient) Close() error

Close gracefully stops the webhook worker.

func (*PersistentCallbackClient) PaymentSucceeded

func (c *PersistentCallbackClient) PaymentSucceeded(ctx context.Context, event PaymentEvent)

PaymentSucceeded queues a payment success webhook for persistent delivery.

func (*PersistentCallbackClient) RefundSucceeded

func (c *PersistentCallbackClient) RefundSucceeded(ctx context.Context, event RefundEvent)

RefundSucceeded queues a refund success webhook for persistent delivery.

type PersistentCallbackOptions

type PersistentCallbackOptions struct {
	Store       storage.Store
	Config      config.CallbacksConfig
	RetryConfig RetryConfig
	Logger      zerolog.Logger
	Metrics     *metrics.Metrics
}

PersistentCallbackOptions configures the persistent callback client.

type RefundEvent

type RefundEvent struct {
	// Idempotency and event metadata (ALWAYS present)
	EventID        string    `json:"eventId"`        // Unique event identifier for idempotency (e.g., "evt_refund_xyz")
	EventType      string    `json:"eventType"`      // Always "refund.succeeded" for this event
	EventTimestamp time.Time `json:"eventTimestamp"` // ISO8601 timestamp when event was created (UTC)

	// Refund details
	RefundID           string            `json:"refundId"`
	OriginalPurchaseID string            `json:"originalPurchaseId"`
	RecipientWallet    string            `json:"recipientWallet"`
	AtomicAmount       int64             `json:"atomicAmount"` // Amount in atomic units (e.g., 10500000 for 10.5 USDC with 6 decimals)
	Token              string            `json:"token"`
	ProcessedBy        string            `json:"processedBy"` // Server wallet that executed refund
	Signature          string            `json:"signature"`
	Reason             string            `json:"reason,omitempty"`
	Metadata           map[string]string `json:"metadata,omitempty"`
	RefundedAt         time.Time         `json:"refundedAt"`
}

RefundEvent encapsulates the essential information about a completed refund. IMPORTANT: EventID is the idempotency key - webhook consumers MUST use this to prevent duplicate processing.

type RetryConfig

type RetryConfig struct {
	MaxAttempts     int           // Maximum retry attempts (default: 5)
	InitialInterval time.Duration // Initial backoff interval (default: 1s)
	MaxInterval     time.Duration // Maximum backoff interval (default: 5m)
	Multiplier      float64       // Backoff multiplier (default: 2.0)
	Timeout         time.Duration // Per-attempt timeout (default: 10s)
}

RetryConfig holds webhook retry configuration.

func DefaultRetryConfig

func DefaultRetryConfig() RetryConfig

DefaultRetryConfig returns sensible defaults for webhook retries.

type RetryOption

type RetryOption func(*RetryableClient)

RetryOption customizes the retry client behavior.

func WithDLQStore

func WithDLQStore(store DLQStore) RetryOption

WithDLQStore enables dead letter queue for failed webhooks.

func WithMetrics

func WithMetrics(metrics *metrics.Metrics) RetryOption

WithMetrics sets the metrics collector for webhook observability.

func WithRetryConfig

func WithRetryConfig(cfg RetryConfig) RetryOption

WithRetryConfig sets custom retry configuration.

func WithRetryLogger

func WithRetryLogger(logger zerolog.Logger) RetryOption

WithRetryLogger sets a custom logger for retry operations.

type RetryableClient

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

RetryableClient posts payment events with exponential backoff retry logic.

func (*RetryableClient) PaymentSucceeded

func (c *RetryableClient) PaymentSucceeded(ctx context.Context, event PaymentEvent)

PaymentSucceeded dispatches the payment event asynchronously with retry logic. IMPORTANT: EventID is generated once and preserved across all retry attempts for idempotency.

func (*RetryableClient) RefundSucceeded

func (c *RetryableClient) RefundSucceeded(ctx context.Context, event RefundEvent)

RefundSucceeded dispatches the refund event asynchronously with retry logic. IMPORTANT: EventID is generated once and preserved across all retry attempts for idempotency.

type WebhookQueueWorker

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

WebhookQueueWorker processes webhooks from the persistent queue.

func NewWebhookQueueWorker

func NewWebhookQueueWorker(opts WebhookQueueWorkerOptions) *WebhookQueueWorker

NewWebhookQueueWorker creates a new webhook queue worker.

func (*WebhookQueueWorker) EnqueuePaymentWebhook

func (w *WebhookQueueWorker) EnqueuePaymentWebhook(ctx context.Context, event PaymentEvent) error

EnqueuePaymentWebhook adds a payment webhook to the persistent queue.

func (*WebhookQueueWorker) EnqueueRefundWebhook

func (w *WebhookQueueWorker) EnqueueRefundWebhook(ctx context.Context, event RefundEvent) error

EnqueueRefundWebhook adds a refund webhook to the persistent queue.

func (*WebhookQueueWorker) Start

func (w *WebhookQueueWorker) Start(ctx context.Context)

Start begins processing webhooks from the queue.

func (*WebhookQueueWorker) Stop

func (w *WebhookQueueWorker) Stop()

Stop gracefully stops the worker.

type WebhookQueueWorkerOptions

type WebhookQueueWorkerOptions struct {
	Store        storage.Store
	Config       config.CallbacksConfig
	RetryConfig  RetryConfig
	Logger       zerolog.Logger
	Metrics      *metrics.Metrics
	PollInterval time.Duration // How often to poll for pending webhooks (default: 5s)
}

WebhookQueueWorkerOptions configures the webhook queue worker.

Jump to

Keyboard shortcuts

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