sagapay

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 13 Imported by: 0

README

SagaPay Go SDK

Go SDK for SagaPay - the world's first free, non-custodial blockchain payment gateway service provider. This SDK enables Go developers to seamlessly integrate cryptocurrency payments without holding customer funds. With enterprise-grade security and zero transaction fees, SagaPay empowers merchants to accept crypto payments across multiple blockchains while maintaining full control of their digital assets.

Installation

go get github.com/rootdigit/sagapay-go-sdk

Quick Start

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/rootdigit/sagapay-go-sdk"
)

func main() {
	// Initialize the SagaPay client
	client, err := sagapay.NewClient(sagapay.Config{
		APIKey:    "your-api-key",
		APISecret: "your-api-secret",
	})
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	// Create a deposit address
	depositResponse, err := client.CreateDeposit(context.Background(), sagapay.CreateDepositParams{
		NetworkType:     sagapay.NetworkTypeBEP20,
		ContractAddress: "0", // Use '0' for native tokens (BNB)
		Amount:          "1.5",
		IPNUrl:          "https://yourwebsite.com/webhook",
		UDF:             "order-123",
		Type:            sagapay.AddressTypeTemporary,
	})
	if err != nil {
		log.Fatalf("Failed to create deposit: %v", err)
	}

	fmt.Printf("Deposit address created: %s\n", depositResponse.Address)
}

Features

  • Deposit address generation
  • Withdrawal processing
  • Transaction status checking
  • Wallet balance fetching
  • Multi-chain support (ERC20, BEP20, TRC20, POLYGON, SOLANA)
  • Webhook notifications (IPN)
  • Custom UDF field support
  • Non-custodial architecture
  • Context support for proper cancellation handling

API Reference

Create Deposit
transferBalance := true
depositResponse, err := client.CreateDeposit(ctx, sagapay.CreateDepositParams{
    NetworkType:     sagapay.NetworkTypeBEP20,     // Required: Blockchain network type
    ContractAddress: "0",                          // Required: Contract address or '0' for native coins
    Amount:          "1.5",                        // Required: Expected deposit amount
    IPNUrl:          "https://example.com/webhook", // Required: URL for notifications
    UDF:             "order-123",                  // Optional: User-defined field
    Type:            sagapay.AddressTypeTemporary, // Optional: TEMPORARY or PERMANENT
    TransferBalance: &transferBalance,             // Optional: defaults to true when omitted
})
Create Withdrawal
withdrawalResponse, err := client.CreateWithdrawal(ctx, sagapay.CreateWithdrawalParams{
    NetworkType:     sagapay.NetworkTypeERC20,
    ContractAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT on Ethereum
    Address:         "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    Amount:          "10.5",
    IPNUrl:          "https://example.com/webhook",
    UDF:             "withdrawal-456",
})
Check Transaction Status
// By address
statusResponse, err := client.CheckTransactionStatus(
    ctx,
    sagapay.TransactionTypeDeposit,
    sagapay.CheckTransactionStatusOptions{
        Address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    },
)

// By transaction ID
statusResponse, err := client.CheckTransactionStatus(
    ctx,
    sagapay.TransactionTypeDeposit,
    sagapay.CheckTransactionStatusOptions{
        ID: "deposit-uuid",
    },
)
Fetch Wallet Balance
balanceResponse, err := client.FetchWalletBalance(
    ctx,
    "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Address
    sagapay.NetworkTypeERC20,                      // Network type
    "0xdAC17F958D2ee523a2206206994597C13D831ec7", // Contract address
)
Verify IPN

VerifyIPN confirms a received webhook (IPN) notification against the SagaPay API and is the primary way to check that a notification is genuine. The API credentials are sent in the request body for this endpoint, not in headers.

verification, err := client.VerifyIPN(ctx, sagapay.VerifyIPNParams{
    TxnHash: payload.TxHash,        // Transaction hash from the notification
    Type:    sagapay.IPNTypeDeposit, // IPNTypeDeposit or IPNTypeWithdrawal (uppercase)
    Amount:  payload.Amount,
    Address: payload.Address,
})
if err != nil {
    log.Fatalf("Failed to verify IPN: %v", err)
}
if verification.Verified {
    // The notification is genuine
}

Handling Webhooks (IPN)

SagaPay sends webhook notifications to your specified ipnUrl when a transaction completes. Delivery is at-least-once, so the same notification may arrive more than once - make your handling idempotent.

Use the WebhookHandler to parse notifications and client.VerifyIPN to confirm them:

package main

import (
    "context"
    "errors"
    "log"
    "net/http"
    "time"

    "github.com/rootdigit/sagapay-go-sdk"
)

func main() {
    client, err := sagapay.NewClient(sagapay.Config{
        APIKey:    "your-api-key",
        APISecret: "your-api-secret",
    })
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    // Create a webhook handler with your platform-issued IPN secret (an
    // optional feature) - this is NOT your API secret. Pass "" if you have
    // not been issued one; signature verification is then skipped and the
    // VerifyIPN call below is the primary check.
    webhookHandler := sagapay.NewWebhookHandler("")

    // Set up a handler for webhook notifications
    http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
        // Parse the webhook (the signature is verified if an IPN secret is set)
        payload, err := webhookHandler.HandleRequest(r)
        if err != nil {
            log.Printf("Error processing webhook: %v", err)
            sagapay.SendErrorResponse(w, err)
            return
        }

        // Confirm the notification with SagaPay - the primary check
        ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second)
        defer cancel()
        verification, err := client.VerifyIPN(ctx, sagapay.VerifyIPNParams{
            TxnHash: payload.TxHash,
            Type:    payload.Type,
            Amount:  payload.Amount,
            Address: payload.Address,
        })
        if err != nil {
            log.Printf("Error verifying IPN: %v", err)
            sagapay.SendErrorResponse(w, err)
            return
        }
        if !verification.Verified {
            sagapay.SendErrorResponse(w, errors.New("IPN not verified"))
            return
        }

        // Handle the notification by type (status is currently always COMPLETED)
        switch payload.Type {
        case sagapay.IPNTypeDeposit:
            // Payment successful, update your database
            log.Printf("Deposit %s completed", payload.ID)
        case sagapay.IPNTypeWithdrawal:
            log.Printf("Withdrawal %s completed", payload.ID)
        }

        // Send a success response
        sagapay.SendSuccessResponse(w)
    })

    // Start the server
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Webhook Payload Format

When SagaPay sends a webhook to your endpoint, it will include the following payload:

{
  "id": "transaction-uuid",
  "type": "DEPOSIT|WITHDRAWAL",
  "status": "COMPLETED",
  "address": "0x123abc...",
  "networkType": "ERC20|BEP20|TRC20|POLYGON|SOLANA",
  "amount": "10.5",
  "udf": "your-optional-user-defined-field",
  "txHash": "0xabc123...",
  "timestamp": "2025-03-16T14:30:00Z"
}

Notes:

  • type is uppercase (DEPOSIT or WITHDRAWAL), unlike the lowercase values used in API query parameters.
  • status is currently always COMPLETED - IPNs are only sent for completed transactions.
  • udf and txHash may be null.
  • Delivery is at-least-once: process notifications idempotently.
Signature Header

If you have been issued a platform IPN secret (an optional feature), each webhook request is signed with the header:

X-Sagapay-Signature: sha256=<hex HMAC-SHA256 of the exact raw request body>

The HMAC is keyed with the platform-issued IPN secret, NOT your API secret. WebhookHandler verifies this header automatically when constructed with the secret. Whether or not a signature is present, client.VerifyIPN is the primary way to confirm a notification is genuine.

Error Handling

The SDK includes comprehensive error handling:

depositResponse, err := client.CreateDeposit(ctx, params)
if err != nil {
    // Check if it's an API error
    if apiErr, ok := err.(*sagapay.APIError); ok {
        fmt.Printf("API Error (HTTP %d): %s\n", apiErr.Code, apiErr.ErrMessage)
        return
    }
    
    // Handle other errors
    fmt.Printf("Error: %v\n", err)
    return
}

License

This SDK is released under the MIT License.

Support

For questions or support, please contact support@sagapay.net or visit https://sagapay.net.

Documentation

Overview

Package sagapay provides a Go client for the SagaPay blockchain payment gateway API.

SagaPay is the world's first free, non-custodial blockchain payment gateway service provider. This package enables Go developers to integrate cryptocurrency payments without holding customer funds.

Index

Constants

View Source
const (
	// DefaultBaseURL is the default base URL for the SagaPay API
	DefaultBaseURL = "https://api2.sagapay.net"

	// DefaultTimeout is the default timeout for API requests
	DefaultTimeout = 30 * time.Second
)

Variables

This section is empty.

Functions

func SendErrorResponse

func SendErrorResponse(w http.ResponseWriter, err error)

SendErrorResponse sends an error response for a webhook

func SendSuccessResponse

func SendSuccessResponse(w http.ResponseWriter)

SendSuccessResponse sends a success response for a webhook

Types

type APIError

type APIError struct {
	// ErrMessage is the message from the API's "error" field
	ErrMessage string `json:"error"`

	// Code is the HTTP status code of the error response
	Code int `json:"-"`
}

APIError represents an error response from the API

func (*APIError) Error

func (e *APIError) Error() string

Error implements the error interface

type AddressType

type AddressType string

AddressType represents the type of address

const (
	AddressTypeTemporary AddressType = "TEMPORARY"
	AddressTypePermanent AddressType = "PERMANENT"
)

Address types

type Balance

type Balance struct {
	Raw       string `json:"raw"`
	Formatted string `json:"formatted"`
}

Balance represents a wallet balance

type CheckTransactionStatusOptions

type CheckTransactionStatusOptions struct {
	Address string
	ID      string
}

CheckTransactionStatusOptions holds optional parameters for CheckTransactionStatus

type Client

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

Client is the SagaPay API client

func NewClient

func NewClient(config Config) (*Client, error)

NewClient creates a new SagaPay API client

func (*Client) CheckTransactionStatus

func (c *Client) CheckTransactionStatus(ctx context.Context, transactionType TransactionType, opts CheckTransactionStatusOptions) (*TransactionStatusResponse, error)

CheckTransactionStatus gets the status of transactions by address or ID

func (*Client) CreateDeposit

func (c *Client) CreateDeposit(ctx context.Context, params CreateDepositParams) (*DepositResponse, error)

CreateDeposit creates a new deposit address for receiving cryptocurrency

func (*Client) CreateWithdrawal

func (c *Client) CreateWithdrawal(ctx context.Context, params CreateWithdrawalParams) (*WithdrawalResponse, error)

CreateWithdrawal creates a cryptocurrency withdrawal request

func (*Client) FetchWalletBalance

func (c *Client) FetchWalletBalance(ctx context.Context, address string, networkType NetworkType, contractAddress string) (*WalletBalanceResponse, error)

FetchWalletBalance gets the balance of a specific wallet address for a token or native currency

func (*Client) VerifyIPN

func (c *Client) VerifyIPN(ctx context.Context, params VerifyIPNParams) (*VerifyIPNResponse, error)

VerifyIPN verifies an IPN notification against the SagaPay API. This is the primary way to confirm that a received webhook notification is genuine.

The verify-ipn endpoint takes the API credentials in the request body rather than in headers, so this request is sent without the authentication headers.

type Config

type Config struct {
	// BaseURL is the base URL for the SagaPay API
	BaseURL string

	// APIKey is your SagaPay API key
	APIKey string

	// APISecret is your SagaPay API secret
	APISecret string

	// Timeout is the timeout for API requests
	Timeout time.Duration

	// HTTPClient is the HTTP client to use for API requests
	HTTPClient *http.Client
}

Config contains the configuration options for the SagaPay client

type CreateDepositParams

type CreateDepositParams struct {
	NetworkType     NetworkType `json:"networkType"`
	ContractAddress string      `json:"contractAddress"`
	Amount          string      `json:"amount"`
	IPNUrl          string      `json:"ipnUrl"`
	UDF             string      `json:"udf,omitempty"`
	Type            AddressType `json:"type,omitempty"`
	TransferBalance *bool       `json:"transferBalance,omitempty"` // Optional: defaults to true when omitted
}

CreateDepositParams represents the parameters for creating a deposit

func (*CreateDepositParams) Validate

func (p *CreateDepositParams) Validate() error

Validate validates the create deposit parameters

type CreateWithdrawalParams

type CreateWithdrawalParams struct {
	NetworkType     NetworkType `json:"networkType"`
	ContractAddress string      `json:"contractAddress"`
	Address         string      `json:"address"`
	Amount          string      `json:"amount"`
	IPNUrl          string      `json:"ipnUrl"`
	UDF             string      `json:"udf,omitempty"`
}

CreateWithdrawalParams represents the parameters for creating a withdrawal

func (*CreateWithdrawalParams) Validate

func (p *CreateWithdrawalParams) Validate() error

Validate validates the create withdrawal parameters

type DepositResponse

type DepositResponse struct {
	ID        string            `json:"id"`
	Address   string            `json:"address"`
	ExpiresAt *time.Time        `json:"expiresAt"`
	Amount    string            `json:"amount"`
	Status    TransactionStatus `json:"status"`
}

DepositResponse represents the response from creating a deposit

type IPNType

type IPNType string

IPNType represents the transaction type reported in IPN (webhook) notifications. Unlike TransactionType, IPN notifications use uppercase values.

const (
	IPNTypeDeposit    IPNType = "DEPOSIT"
	IPNTypeWithdrawal IPNType = "WITHDRAWAL"
)

IPN types

type NetworkType

type NetworkType string

NetworkType represents the blockchain network type

const (
	NetworkTypeERC20   NetworkType = "ERC20"
	NetworkTypeBEP20   NetworkType = "BEP20"
	NetworkTypeTRC20   NetworkType = "TRC20"
	NetworkTypePOLYGON NetworkType = "POLYGON"
	NetworkTypeSOLANA  NetworkType = "SOLANA"
)

Network types

type Token

type Token struct {
	NetworkType     NetworkType `json:"networkType"`
	ContractAddress string      `json:"contractAddress"`
	Symbol          string      `json:"symbol"`
	Name            string      `json:"name"`
	Decimals        int         `json:"decimals"`
}

Token represents a cryptocurrency token

type Transaction

type Transaction struct {
	ID              string            `json:"id"`
	TransactionType TransactionType   `json:"transactionType"`
	Status          TransactionStatus `json:"status"`
	Amount          string            `json:"amount"`
	CreatedAt       time.Time         `json:"createdAt"`
	UpdatedAt       time.Time         `json:"updatedAt"`
	TxHash          string            `json:"txHash,omitempty"`
	NetworkType     NetworkType       `json:"networkType"`
	ContractAddress string            `json:"contractAddress"`
	Address         string            `json:"address"`
	UDF             string            `json:"udf,omitempty"`
	Token           Token             `json:"token"`
	Confirmations   *int              `json:"confirmations,omitempty"` // Deposit transactions only
	Fee             *string           `json:"fee,omitempty"`           // Withdrawal transactions only
	ProcessedAt     *time.Time        `json:"processedAt,omitempty"`   // Withdrawal transactions only, nullable
}

Transaction represents a cryptocurrency transaction

type TransactionStatus

type TransactionStatus string

TransactionStatus represents the status of a transaction

const (
	TransactionStatusPending    TransactionStatus = "PENDING"
	TransactionStatusProcessing TransactionStatus = "PROCESSING"
	TransactionStatusCompleted  TransactionStatus = "COMPLETED"
	TransactionStatusFailed     TransactionStatus = "FAILED"
	TransactionStatusCancelled  TransactionStatus = "CANCELLED"
)

Transaction statuses

type TransactionStatusResponse

type TransactionStatusResponse struct {
	Address         string          `json:"address"`
	TransactionType TransactionType `json:"transactionType"`
	Count           int             `json:"count"`
	Transactions    []Transaction   `json:"transactions"`
}

TransactionStatusResponse represents the response from checking transaction status

type TransactionType

type TransactionType string

TransactionType represents the type of transaction

const (
	TransactionTypeDeposit    TransactionType = "deposit"
	TransactionTypeWithdrawal TransactionType = "withdrawal"
)

Transaction types

type VerifyIPNParams

type VerifyIPNParams struct {
	TxnHash string  `json:"txnHash"`
	Type    IPNType `json:"type"`
	Amount  string  `json:"amount"`
	Address string  `json:"address"`
}

VerifyIPNParams represents the parameters for verifying an IPN notification

func (*VerifyIPNParams) Validate

func (p *VerifyIPNParams) Validate() error

Validate validates the verify IPN parameters

type VerifyIPNResponse

type VerifyIPNResponse struct {
	Verified bool `json:"verified"`
}

VerifyIPNResponse represents the response from verifying an IPN notification

type WalletBalanceResponse

type WalletBalanceResponse struct {
	Address         string      `json:"address"`
	NetworkType     NetworkType `json:"networkType"`
	ContractAddress string      `json:"contractAddress"`
	Token           Token       `json:"token"`
	Balance         Balance     `json:"balance"`
}

WalletBalanceResponse represents the response from fetching wallet balance

type WebhookHandler

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

WebhookHandler handles SagaPay webhook (IPN) notifications

func NewWebhookHandler

func NewWebhookHandler(ipnSecret string) *WebhookHandler

NewWebhookHandler creates a new webhook handler.

ipnSecret is the platform-issued IPN signing secret (an optional feature), NOT your API secret. If ipnSecret is empty, signature verification is skipped and webhook payloads are only parsed. Either way, Client.VerifyIPN is the primary check for confirming a notification is genuine.

func (*WebhookHandler) HandleRequest

func (h *WebhookHandler) HandleRequest(r *http.Request) (*WebhookPayload, error)

HandleRequest processes a webhook notification from an HTTP request

func (*WebhookHandler) ProcessWebhook

func (h *WebhookHandler) ProcessWebhook(body []byte, signature string) (*WebhookPayload, error)

ProcessWebhook processes a webhook notification from raw body and signature.

If the handler was created without an IPN secret, signature verification is skipped and the payload is only parsed; use Client.VerifyIPN as the primary check before trusting the notification.

func (*WebhookHandler) VerifySignature

func (h *WebhookHandler) VerifySignature(payload []byte, signature string) bool

VerifySignature verifies the HMAC-SHA256 signature of a webhook payload. The signature is the value of the X-Sagapay-Signature header, either in the "sha256=<hex>" form sent by SagaPay or as bare hex.

type WebhookPayload

type WebhookPayload struct {
	ID          string            `json:"id"`
	Type        IPNType           `json:"type"`
	Status      TransactionStatus `json:"status"` // Currently always COMPLETED
	Address     string            `json:"address"`
	NetworkType NetworkType       `json:"networkType"`
	Amount      string            `json:"amount"`
	UDF         string            `json:"udf,omitempty"`
	TxHash      string            `json:"txHash,omitempty"`
	Timestamp   time.Time         `json:"timestamp"`
}

WebhookPayload represents the payload sent in webhook (IPN) notifications

type WithdrawalResponse

type WithdrawalResponse struct {
	ID     string            `json:"id"`
	Status TransactionStatus `json:"status"`
	Fee    string            `json:"fee"`
}

WithdrawalResponse represents the response from creating a withdrawal

Directories

Path Synopsis
webhook command

Jump to

Keyboard shortcuts

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