Documentation
¶
Overview ¶
Package squad provides a Go client for the Squad by GTCO payment gateway API.
Getting Started ¶
client := squad.New("sandbox_sk_your_key_here")
resp, err := client.Transactions.InitiatePayment(ctx, &squad.InitiatePaymentParams{
Email: "customer@example.com",
Amount: squad.NGN(5000), // ₦5,000
Currency: "NGN",
CallbackURL: "https://yoursite.com/callback",
})
Environments ¶
The sandbox environment is automatically selected when your key starts with "sandbox_sk_". For production, use your live key or explicitly call WithProduction().
Idempotency ¶
key, _ := squad.GenerateIdempotencyKey() ctx = squad.WithIdempotencyKey(ctx, key) resp, err := client.Transactions.InitiatePayment(ctx, params)
Pagination ¶
iter := client.Transfers.All(ctx, nil)
for iter.Next() {
fmt.Println(iter.Item().TransactionRef)
}
Webhook Verification ¶
event, err := squad.ParseWebhook(body, r.Header.Get("x-squad-signature"), secretKey)
Webhook Router ¶
router := squad.NewWebhookRouter(secretKey).
OnTransactionSuccess(handlePayment).
OnVirtualAccountCredit(handleCredit)
http.Handle("/webhook/squad", router)
Index ¶
- Constants
- Variables
- func FromCents(cents int64) float64
- func FromKobo(kobo int64) float64
- func GenerateIdempotencyKey() (string, error)
- func IsBadRequest(err error) bool
- func IsNotFound(err error) bool
- func IsUnauthorized(err error) bool
- func NGN(naira float64) int64
- func USD(dollars float64) int64
- func VerifySignature(payload []byte, signature string, secret string) bool
- func WithIdempotencyKey(ctx context.Context, key string) context.Context
- type AccountLookupResponse
- type BuyAirtimeParams
- type BuyCableParams
- type BuyDataParams
- type BuyElectricityParams
- type CablePackage
- type CablePackagesResponse
- type ChargeToken
- type Client
- type CreateSubMerchantParams
- type CreateVirtualAccountParams
- type CustomerInfo
- type DataPlan
- type DataPlansResponse
- type DeleteSubMerchantResponse
- type Dispute
- type DisputeActionResponse
- type DisputeEvidence
- type DisputeListParams
- type DisputeListResponse
- type DisputeService
- func (s *DisputeService) AcceptDispute(ctx context.Context, ticketID string) (*DisputeActionResponse, error)
- func (s *DisputeService) All(ctx context.Context, params *DisputeListParams) *Iter[Dispute]
- func (s *DisputeService) GetAllDisputes(ctx context.Context, params *DisputeListParams) (*DisputeListResponse, error)
- func (s *DisputeService) GetDisputeDetail(ctx context.Context, ticketID string) (*Dispute, error)
- func (s *DisputeService) GetDisputeEvidence(ctx context.Context, ticketID string) (*DisputeEvidence, error)
- func (s *DisputeService) RejectDispute(ctx context.Context, ticketID string) (*DisputeActionResponse, error)
- func (s *DisputeService) UploadEvidence(ctx context.Context, ticketID string, fileData []byte, fileName string) (*EvidenceUploadResponse, error)
- type ElectricityBiller
- type ElectricityBillersResponse
- type ElectricityResponse
- type Error
- type EventType
- type EvidenceUploadResponse
- type FundsTransferParams
- type InitiatePaymentParams
- type InitiatePaymentResponse
- type IntraTransferParams
- type Iter
- type Logger
- type MerchantInfo
- type MissedWebhookParams
- type MissedWebhookResponse
- type Option
- func WithAfterResponse(fn func(*http.Request, *http.Response, time.Duration)) Option
- func WithAutoIdempotency() Option
- func WithBaseURL(url string) Option
- func WithBeforeRequest(fn func(*http.Request)) Option
- func WithHTTPClient(hc *http.Client) Option
- func WithLogger(l Logger) Option
- func WithProduction() Option
- func WithSandbox() Option
- func WithTimeout(d time.Duration) Option
- func WithUserAgent(ua string) Option
- type RefundTransactionParams
- type RefundTransactionResponse
- type SMSResponse
- type SendSMSParams
- type SimulateResponse
- type SimulateVirtualAccountParams
- type SubMerchant
- type SubMerchantListParams
- type SubMerchantListResponse
- type SubMerchantService
- func (s *SubMerchantService) All(ctx context.Context, params *SubMerchantListParams) *Iter[SubMerchant]
- func (s *SubMerchantService) Create(ctx context.Context, params *CreateSubMerchantParams) (*SubMerchant, error)
- func (s *SubMerchantService) Delete(ctx context.Context, merchantID string) (*DeleteSubMerchantResponse, error)
- func (s *SubMerchantService) Get(ctx context.Context, merchantID string) (*SubMerchant, error)
- func (s *SubMerchantService) List(ctx context.Context, params *SubMerchantListParams) (*SubMerchantListResponse, error)
- type TransactionService
- func (s *TransactionService) AllMissedWebhooks(ctx context.Context, params *MissedWebhookParams) *Iter[VerifyTransactionResponse]
- func (s *TransactionService) GetMissedWebhookTransactions(ctx context.Context, params *MissedWebhookParams) (*MissedWebhookResponse, error)
- func (s *TransactionService) GetUSSDbanks(ctx context.Context) (*USSDbanksResponse, error)
- func (s *TransactionService) InitiatePayment(ctx context.Context, params *InitiatePaymentParams) (*InitiatePaymentResponse, error)
- func (s *TransactionService) RefundTransaction(ctx context.Context, params *RefundTransactionParams) (*RefundTransactionResponse, error)
- func (s *TransactionService) VerifyTransaction(ctx context.Context, transactionRef string) (*VerifyTransactionResponse, error)
- type TransferListParams
- type TransferListResponse
- type TransferResponse
- type TransferService
- func (s *TransferService) AccountLookup(ctx context.Context, bankCode, accountNumber string) (*AccountLookupResponse, error)
- func (s *TransferService) All(ctx context.Context, params *TransferListParams) *Iter[TransferStatusResponse]
- func (s *TransferService) FundsTransfer(ctx context.Context, params *FundsTransferParams) (*TransferResponse, error)
- func (s *TransferService) GetAllTransactions(ctx context.Context, params *TransferListParams) (*TransferListResponse, error)
- func (s *TransferService) GetTransactionStatus(ctx context.Context, transactionRef string) (*TransferStatusResponse, error)
- func (s *TransferService) IntraTransfer(ctx context.Context, params *IntraTransferParams) (*TransferResponse, error)
- type TransferStatusResponse
- type USSDBank
- type USSDbanksResponse
- type UpdateVirtualAccountParams
- type VASService
- func (s *VASService) BuyAirtime(ctx context.Context, params *BuyAirtimeParams) (*VASTransactionResponse, error)
- func (s *VASService) BuyCable(ctx context.Context, params *BuyCableParams) (*VASTransactionResponse, error)
- func (s *VASService) BuyData(ctx context.Context, params *BuyDataParams) (*VASTransactionResponse, error)
- func (s *VASService) BuyElectricity(ctx context.Context, params *BuyElectricityParams) (*ElectricityResponse, error)
- func (s *VASService) GetCablePackages(ctx context.Context, cableProvider string) (*CablePackagesResponse, error)
- func (s *VASService) GetDataPlans(ctx context.Context, networkProvider string) (*DataPlansResponse, error)
- func (s *VASService) GetElectricityBillers(ctx context.Context) (*ElectricityBillersResponse, error)
- func (s *VASService) SendSMS(ctx context.Context, params *SendSMSParams) (*SMSResponse, error)
- type VASTransactionResponse
- type VerifyTransactionResponse
- type VirtualAccount
- type VirtualAccountService
- func (s *VirtualAccountService) AllTransactions(ctx context.Context, customerIdentifier string, params *VirtualAccountTxParams) *Iter[VirtualAccountTransaction]
- func (s *VirtualAccountService) Create(ctx context.Context, params *CreateVirtualAccountParams) (*VirtualAccount, error)
- func (s *VirtualAccountService) GetTransactions(ctx context.Context, customerIdentifier string, params *VirtualAccountTxParams) (*VirtualAccountTxResponse, error)
- func (s *VirtualAccountService) Query(ctx context.Context, virtualAccountNumber string) (*VirtualAccount, error)
- func (s *VirtualAccountService) Simulate(ctx context.Context, params *SimulateVirtualAccountParams) (*SimulateResponse, error)
- func (s *VirtualAccountService) Update(ctx context.Context, params *UpdateVirtualAccountParams) (*VirtualAccount, error)
- type VirtualAccountTransaction
- type VirtualAccountTxParams
- type VirtualAccountTxResponse
- type WebhookDisputeBody
- type WebhookEvent
- type WebhookRouter
- func (r *WebhookRouter) OnDisputeOpened(fn func(context.Context, *WebhookDisputeBody) error) *WebhookRouter
- func (r *WebhookRouter) OnDisputeResolved(fn func(context.Context, *WebhookDisputeBody) error) *WebhookRouter
- func (r *WebhookRouter) OnError(fn func(http.ResponseWriter, *http.Request, error)) *WebhookRouter
- func (r *WebhookRouter) OnTransactionFailed(fn func(context.Context, *WebhookTransactionBody) error) *WebhookRouter
- func (r *WebhookRouter) OnTransactionSuccess(fn func(context.Context, *WebhookTransactionBody) error) *WebhookRouter
- func (r *WebhookRouter) OnTransferFailed(fn func(context.Context, *WebhookTransferBody) error) *WebhookRouter
- func (r *WebhookRouter) OnTransferReversed(fn func(context.Context, *WebhookTransferBody) error) *WebhookRouter
- func (r *WebhookRouter) OnTransferSuccess(fn func(context.Context, *WebhookTransferBody) error) *WebhookRouter
- func (r *WebhookRouter) OnUnknown(fn func(context.Context, *WebhookEvent) error) *WebhookRouter
- func (r *WebhookRouter) OnVirtualAccountCredit(fn func(context.Context, *WebhookVirtualAccountBody) error) *WebhookRouter
- func (r *WebhookRouter) ServeHTTP(w http.ResponseWriter, req *http.Request)
- type WebhookTransactionBody
- type WebhookTransferBody
- type WebhookVirtualAccountBody
Constants ¶
const ( // Version is the current SDK version. Version = "1.1.0" // DefaultTimeout is the default HTTP request timeout. DefaultTimeout = 30 * time.Second // SandboxBaseURL is the Squad sandbox API base URL. SandboxBaseURL = "https://sandbox-api-d.squadco.com" // ProductionBaseURL is the Squad production API base URL. ProductionBaseURL = "https://api-d.squadco.com" )
Variables ¶
var ( ErrForbidden = &Error{HTTPStatus: 403, Status: 403, Message: "forbidden"} ErrBadRequest = &Error{HTTPStatus: 400, Status: 400, Message: "bad request"} ErrNotFound = &Error{HTTPStatus: 404, Status: 404, Message: "not found"} )
Sentinel errors for common API failure modes.
var ErrInvalidSignature = fmt.Errorf("squad: webhook signature validation failed")
ErrInvalidSignature is returned by ParseWebhook when HMAC-SHA512 validation fails.
Functions ¶
func FromCents ¶
FromCents converts a cents amount back to dollars for display purposes.
squad.FromCents(5000) // → 50.00 ($50.00)
func FromKobo ¶
FromKobo converts a kobo amount back to naira for display purposes.
squad.FromKobo(500000) // → 5000.00 (₦5,000)
func GenerateIdempotencyKey ¶
GenerateIdempotencyKey generates a cryptographically random 32-character hex key. Use this when you don't have a natural business key (e.g. order ID) to use.
key, err := squad.GenerateIdempotencyKey() // Store key alongside the order before initiating payment. ctx = squad.WithIdempotencyKey(ctx, key)
func IsBadRequest ¶
IsBadRequest reports whether err is a 400 validation failure.
func IsNotFound ¶
IsNotFound reports whether err is a 404 not-found failure.
func IsUnauthorized ¶
IsUnauthorized reports whether err is a 401 authorization failure.
func NGN ¶
NGN converts a naira amount to kobo (the lowest denomination used by the Squad API).
squad.NGN(5000) // → 500000 kobo (₦5,000) squad.NGN(1) // → 100 kobo (₦1)
func USD ¶
USD converts a dollar amount to cents (the lowest denomination for USD transactions).
squad.USD(50) // → 5000 cents ($50.00) squad.USD(0.50) // → 50 cents ($0.50)
func VerifySignature ¶
VerifySignature checks whether the HMAC-SHA512 signature matches the payload. signature is the hex-encoded value from the "x-squad-signature" header. secret is the merchant's Squad secret key.
Uses constant-time comparison to prevent timing attacks.
func WithIdempotencyKey ¶
WithIdempotencyKey attaches an idempotency key to the context. The SDK sends it as X-Idempotency-Key on all POST requests, preventing duplicate charges when a request is retried after a network failure.
The key should be unique per business operation and attempt. Store it before making the request so you can reuse it on retry.
key, _ := squad.GenerateIdempotencyKey() ctx = squad.WithIdempotencyKey(ctx, "order-"+orderID+"-"+key) resp, err := client.Transactions.InitiatePayment(ctx, params) // On network error, retry with the SAME ctx to use the same key.
Types ¶
type AccountLookupResponse ¶
type AccountLookupResponse struct {
AccountName string `json:"account_name"`
AccountNumber string `json:"account_number"`
BankCode string `json:"bank_code"`
BankName string `json:"bank_name"`
}
AccountLookupResponse is returned by AccountLookup after verifying a bank account.
type BuyAirtimeParams ¶
type BuyAirtimeParams struct {
PhoneNumber string `json:"phone_number"`
Amount int64 `json:"amount"`
Network string `json:"network_provider"` // "MTN", "AIRTEL", "GLO", "9MOBILE"
TransactionRef string `json:"transaction_ref"`
}
BuyAirtimeParams holds parameters for purchasing airtime. PhoneNumber should be in international format without "+": "2348012345678". Minimum amount is 50 NGN. Charges come from the Squad wallet.
type BuyCableParams ¶
type BuyCableParams struct {
SmartCardNumber string `json:"smart_card_number"`
PackageCode string `json:"package_code"`
Provider string `json:"cable_provider"` // "DSTV", "GOTV", "STARTIMES"
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"amount,omitempty"`
}
BuyCableParams holds parameters for subscribing to a cable TV package.
type BuyDataParams ¶
type BuyDataParams struct {
PhoneNumber string `json:"phone_number"`
PlanCode string `json:"plan_code"`
Network string `json:"network_provider"`
TransactionRef string `json:"transaction_ref"`
}
BuyDataParams holds parameters for purchasing a data bundle.
type BuyElectricityParams ¶
type BuyElectricityParams struct {
MeterNumber string `json:"meter_number"`
Amount int64 `json:"amount"`
BillerCode string `json:"biller_code"`
MeterType string `json:"meter_type"` // "prepaid" or "postpaid"
TransactionRef string `json:"transaction_ref"`
PhoneNumber string `json:"phone_number,omitempty"`
}
BuyElectricityParams holds parameters for purchasing electricity units.
type CablePackage ¶
type CablePackage struct {
PackageCode string `json:"package_code"`
PackageName string `json:"package_name"`
Amount int64 `json:"amount"`
CycleType string `json:"cycle_type"` // "monthly", "quarterly"
}
CablePackage describes a single cable TV subscription package.
type CablePackagesResponse ¶
type CablePackagesResponse struct {
Packages []CablePackage `json:"packages"`
}
CablePackagesResponse holds available cable TV packages for a provider.
type ChargeToken ¶
type ChargeToken struct {
Token string `json:"token"`
ExpiryMonth int `json:"expiry_month"`
ExpiryYear int `json:"expiry_year"`
}
ChargeToken holds card tokenization data used for recurring charges.
type Client ¶
type Client struct {
// Transactions handles payment initiation, verification, and refunds.
Transactions *TransactionService
// VirtualAccounts handles NUBAN virtual account creation and management.
VirtualAccounts *VirtualAccountService
// Transfers handles fund transfers to Nigerian bank accounts.
Transfers *TransferService
// Disputes handles chargeback disputes and evidence submission.
Disputes *DisputeService
// VAS handles value-added services: airtime, data, cable TV, electricity, and SMS.
VAS *VASService
// SubMerchants manages sub-merchant accounts for aggregators and platforms.
SubMerchants *SubMerchantService
// contains filtered or unexported fields
}
Client is the root SDK object. All API services are accessible as fields. A Client is safe for concurrent use across goroutines.
func New ¶
New constructs a ready-to-use Client.
secretKey is your Squad secret key (sandbox_sk_* for sandbox, live secret for production). The sandbox environment is automatically selected when the key starts with "sandbox_sk_". Pass functional options to override defaults.
client := squad.New("sandbox_sk_xxx")
client := squad.New("live_sk_xxx", squad.WithLogger(squad.StdLogger()))
type CreateSubMerchantParams ¶
type CreateSubMerchantParams struct {
DisplayName string `json:"display_name"`
AccountName string `json:"account_name"`
AccountNumber string `json:"account_number"`
BankCode string `json:"bank_code"`
Email string `json:"email"`
MobileNumber string `json:"mobile_number,omitempty"`
}
CreateSubMerchantParams holds parameters for onboarding a sub-merchant. Requires an aggregator-level Squad account.
type CreateVirtualAccountParams ¶
type CreateVirtualAccountParams struct {
CustomerIdentifier string `json:"customer_identifier"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
MiddleName string `json:"middle_name,omitempty"`
MobileNum string `json:"mobile_num"`
Email string `json:"email"`
BVN string `json:"bvn"`
DOB string `json:"dob"` // "DD/MM/YYYY"
Address string `json:"address,omitempty"`
Gender string `json:"gender,omitempty"` // "1" = male, "2" = female
BeneficiaryAccount string `json:"beneficiary_account,omitempty"`
}
CreateVirtualAccountParams holds all parameters to create a NUBAN virtual account. CBN profiling on the Squad dashboard is required before this endpoint is available.
type CustomerInfo ¶
type CustomerInfo struct {
CustomerName string `json:"customer_name"`
CustomerEmail string `json:"customer_email"`
CustomerPhone string `json:"customer_phone_number"`
MerchantID string `json:"merchant_id"`
}
CustomerInfo is embedded in transaction responses.
type DataPlan ¶
type DataPlan struct {
PlanCode string `json:"plan_code"`
PlanName string `json:"plan_name"`
Amount int64 `json:"amount"`
Validity string `json:"validity"`
Network string `json:"network"`
}
DataPlan describes a single data bundle offering for a network provider.
type DataPlansResponse ¶
type DataPlansResponse struct {
Plans []DataPlan `json:"plans"`
}
DataPlansResponse holds available data plans for a network provider.
type DeleteSubMerchantResponse ¶
type DeleteSubMerchantResponse struct {
MerchantID string `json:"merchant_id"`
Status string `json:"status"`
Message string `json:"message"`
}
DeleteSubMerchantResponse is returned when a sub-merchant is removed.
type Dispute ¶
type Dispute struct {
TicketID string `json:"ticket_id"`
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
Status string `json:"dispute_status"`
Reason string `json:"dispute_reason"`
CustomerEmail string `json:"customer_email"`
CustomerName string `json:"customer_name"`
DueDate string `json:"due_date"`
MerchantResponse string `json:"merchant_response"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
Dispute represents a single chargeback or dispute record.
type DisputeActionResponse ¶
type DisputeActionResponse struct {
TicketID string `json:"ticket_id"`
Status string `json:"status"`
Message string `json:"message"`
}
DisputeActionResponse is returned by AcceptDispute and RejectDispute.
type DisputeEvidence ¶
type DisputeEvidence struct {
TicketID string `json:"ticket_id"`
EvidenceURL string `json:"evidence_url"`
FileName string `json:"file_name"`
UploadedAt string `json:"uploaded_at"`
}
DisputeEvidence represents evidence attached to a dispute.
type DisputeListParams ¶
type DisputeListParams struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
StartDate string `json:"start_date,omitempty"`
EndDate string `json:"end_date,omitempty"`
Status string `json:"status,omitempty"` // "open", "closed", "pending"
}
DisputeListParams holds pagination and filter parameters for listing disputes.
type DisputeListResponse ¶
type DisputeListResponse struct {
Disputes []Dispute `json:"disputes"`
Total int `json:"total"`
Page int `json:"page"`
PerPage int `json:"per_page"`
}
DisputeListResponse holds a paginated list of disputes.
type DisputeService ¶
type DisputeService struct {
// contains filtered or unexported fields
}
DisputeService handles chargeback disputes and evidence submission.
func (*DisputeService) AcceptDispute ¶
func (s *DisputeService) AcceptDispute(ctx context.Context, ticketID string) (*DisputeActionResponse, error)
AcceptDispute accepts a chargeback (merchant concedes the dispute).
func (*DisputeService) All ¶
func (s *DisputeService) All(ctx context.Context, params *DisputeListParams) *Iter[Dispute]
All returns a lazy iterator over all disputes, fetching pages on demand. Filters from params (Status, StartDate, EndDate) are preserved across pages.
iter := client.Disputes.All(ctx, &squad.DisputeListParams{Status: "open"})
for iter.Next() {
d := iter.Item()
fmt.Println(d.TicketID, d.Reason)
}
func (*DisputeService) GetAllDisputes ¶
func (s *DisputeService) GetAllDisputes(ctx context.Context, params *DisputeListParams) (*DisputeListResponse, error)
GetAllDisputes retrieves a paginated list of all disputes on the merchant account.
func (*DisputeService) GetDisputeDetail ¶
GetDisputeDetail retrieves the full details of a single dispute by its ticket ID.
func (*DisputeService) GetDisputeEvidence ¶
func (s *DisputeService) GetDisputeEvidence(ctx context.Context, ticketID string) (*DisputeEvidence, error)
GetDisputeEvidence retrieves any previously uploaded evidence for a dispute.
func (*DisputeService) RejectDispute ¶
func (s *DisputeService) RejectDispute(ctx context.Context, ticketID string) (*DisputeActionResponse, error)
RejectDispute contests a chargeback (merchant disputes the claim). Evidence must be uploaded via UploadEvidence before calling this method.
func (*DisputeService) UploadEvidence ¶
func (s *DisputeService) UploadEvidence(ctx context.Context, ticketID string, fileData []byte, fileName string) (*EvidenceUploadResponse, error)
UploadEvidence uploads a file as evidence for a dispute. fileData is the raw file bytes (PDF, PNG, or JPG). fileName includes the extension. Call this before RejectDispute — evidence must be present to contest a chargeback.
type ElectricityBiller ¶
type ElectricityBiller struct {
BillerCode string `json:"biller_code"`
BillerName string `json:"biller_name"`
MeterTypes []string `json:"meter_types"` // ["prepaid", "postpaid"]
}
ElectricityBiller describes a DISCO (electricity distribution company).
type ElectricityBillersResponse ¶
type ElectricityBillersResponse struct {
Billers []ElectricityBiller `json:"billers"`
}
ElectricityBillersResponse holds the list of available electricity DISCOs.
type ElectricityResponse ¶
type ElectricityResponse struct {
VASTransactionResponse
MeterNumber string `json:"meter_number"`
Units string `json:"units"`
ElectricityToken string `json:"electricity_token"`
}
ElectricityResponse is returned by BuyElectricity, including the token for the meter.
type Error ¶
Error represents a Squad API error response. It wraps both the HTTP-level status and Squad's application-level status code.
type EventType ¶
type EventType string
EventType is the string identifier for a Squad webhook event.
const ( EventTransactionSuccess EventType = "charge_successful" EventTransactionFailed EventType = "charge_failed" EventVirtualAccountCredit EventType = "virtualaccount_credited" EventTransferSuccess EventType = "transfer_successful" EventTransferFailed EventType = "transfer_failed" EventTransferReversed EventType = "transfer_reversed" EventDisputeOpened EventType = "dispute_opened" EventDisputeResolved EventType = "dispute_resolved" )
Squad webhook event type constants. Squad uses snake_case with underscores (confirmed from live sandbox payloads).
type EvidenceUploadResponse ¶
type EvidenceUploadResponse struct {
TicketID string `json:"ticket_id"`
FileName string `json:"file_name"`
UploadURL string `json:"upload_url"`
Status string `json:"status"`
}
EvidenceUploadResponse is returned after a successful evidence upload.
type FundsTransferParams ¶
type FundsTransferParams struct {
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"amount"`
BankCode string `json:"bank_code"`
AccountNumber string `json:"account_number"`
AccountName string `json:"account_name"`
Currency string `json:"currency_id"` // "NGN"
Remark string `json:"remark,omitempty"`
}
FundsTransferParams holds parameters for transferring funds to a Nigerian bank account. Amount is in kobo (lowest denomination). Settlement is T+1 by default.
type InitiatePaymentParams ¶
type InitiatePaymentParams struct {
Email string `json:"email"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
InitiatorCustomerID string `json:"initiator_customer_id,omitempty"`
TransactionRef string `json:"transaction_ref,omitempty"`
CallbackURL string `json:"callback_url,omitempty"`
PaymentChannels []string `json:"payment_channels,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
PassCharge bool `json:"pass_charge,omitempty"`
CustomerName string `json:"customer_name,omitempty"`
IsRecurring bool `json:"is_recurring,omitempty"`
PlanCode string `json:"plan_code,omitempty"`
ChargeToken *ChargeToken `json:"charge_token,omitempty"`
}
InitiatePaymentParams holds all parameters for creating a new payment transaction. Amount must be in the lowest currency denomination (kobo for NGN: 100000 = ₦1,000).
type InitiatePaymentResponse ¶
type InitiatePaymentResponse struct {
// CheckoutURL is returned by Squad when initiate_type is "inline".
// The SDK builds it from TransactionRef as a fallback if Squad omits it.
CheckoutURL string `json:"checkout_url"`
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"transaction_amount"`
Currency string `json:"currency"`
CallbackURL string `json:"callback_url"`
IsRecurring bool `json:"is_recurring"`
AuthorizedChannels []string `json:"authorized_channels"`
MerchantInfo MerchantInfo `json:"merchant_info"`
}
InitiatePaymentResponse is the Data payload returned by InitiatePayment. Redirect the end-user to CheckoutURL to complete payment.
type IntraTransferParams ¶
type IntraTransferParams struct {
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"amount"`
SenderIdentifier string `json:"sender_identifier"`
ReceiverIdentifier string `json:"receiver_identifier"`
Narration string `json:"narration,omitempty"`
}
IntraTransferParams holds parameters for a Squad-to-Squad wallet transfer.
type Iter ¶
type Iter[T any] struct { // contains filtered or unexported fields }
Iter is a generic lazy iterator for paginated Squad API responses. Pages are fetched on demand — only when the current buffer is exhausted.
Usage:
iter := client.Transfers.All(ctx, &squad.TransferListParams{PerPage: 50})
for iter.Next() {
t := iter.Item()
fmt.Println(t.TransactionRef, squad.FromKobo(t.Amount))
}
if err := iter.Err(); err != nil {
log.Fatal(err)
}
type Logger ¶
Logger is the interface for SDK-level request/response logging. Implement this to integrate with your application's logging library.
Compatible with log/slog, go.uber.org/zap, sirupsen/logrus, rs/zerolog, and others. Fields are passed as key-value pairs: key string, value any, key string, value any, ...
// log/slog example:
type slogAdapter struct{ l *slog.Logger }
func (a slogAdapter) Info(msg string, kv ...any) { a.l.Info(msg, kv...) }
func (a slogAdapter) Error(msg string, kv ...any) { a.l.Error(msg, kv...) }
client := squad.New(key, squad.WithLogger(slogAdapter{slog.Default()}))
type MerchantInfo ¶ added in v1.1.1
type MerchantInfo struct {
MerchantName string `json:"merchant_name"`
MerchantID string `json:"merchant_id"`
}
MerchantInfo contains basic merchant identity returned inside payment responses.
type MissedWebhookParams ¶
type MissedWebhookParams struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
Action string `json:"action,omitempty"`
}
MissedWebhookParams holds query parameters for GetMissedWebhookTransactions.
type MissedWebhookResponse ¶
type MissedWebhookResponse struct {
Transactions []VerifyTransactionResponse `json:"transactions"`
Total int `json:"total"`
Page int `json:"page"`
PerPage int `json:"per_page"`
}
MissedWebhookResponse is the Data payload returned by GetMissedWebhookTransactions.
type Option ¶
type Option func(*config)
Option is a functional option for configuring a Client.
func WithAfterResponse ¶
WithAfterResponse registers a hook called after every HTTP response is received. duration is the total round-trip time. Use this for metrics, tracing, or audit logging.
squad.WithAfterResponse(func(req *http.Request, resp *http.Response, d time.Duration) {
metrics.RecordLatency("squad", req.URL.Path, resp.StatusCode, d)
})
func WithAutoIdempotency ¶
func WithAutoIdempotency() Option
WithAutoIdempotency automatically generates and attaches an X-Idempotency-Key header to every POST request that does not already have one set via WithIdempotencyKey. This protects against accidental duplicate charges from network-level retries.
func WithBaseURL ¶
WithBaseURL sets a custom base URL. Useful for proxies, local mocks, or testing. Must include scheme and host with no trailing slash: "https://my-proxy.example.com"
func WithBeforeRequest ¶
WithBeforeRequest registers a hook called before every HTTP request is sent. Use this for custom header injection, request signing, or distributed tracing.
squad.WithBeforeRequest(func(req *http.Request) {
req.Header.Set("X-Correlation-ID", getCorrelationID())
})
func WithHTTPClient ¶
WithHTTPClient replaces the default *http.Client. Use this to inject transports with retry logic, tracing, or custom TLS config.
func WithLogger ¶
WithLogger attaches a Logger to the client for request/response logging. By default all logging is discarded. Use StdLogger() for development output.
client := squad.New(key, squad.WithLogger(squad.StdLogger()))
func WithProduction ¶
func WithProduction() Option
WithProduction explicitly sets the production base URL.
func WithSandbox ¶
func WithSandbox() Option
WithSandbox configures the client to use Squad's sandbox environment. This is also inferred automatically when the secret key starts with "sandbox_sk_".
func WithTimeout ¶
WithTimeout sets the HTTP request timeout, overriding the default 30-second timeout.
func WithUserAgent ¶
WithUserAgent appends a custom string to the User-Agent header.
type RefundTransactionParams ¶
type RefundTransactionParams struct {
GatewayTransactionRef string `json:"gateway_transaction_ref"`
TransactionRef string `json:"transaction_ref"`
RefundType string `json:"refund_type"`
ReasonForRefund string `json:"reason_for_refund"`
Amount int64 `json:"refund_amount,omitempty"`
RRN string `json:"rrn,omitempty"`
}
RefundTransactionParams holds parameters for initiating a transaction refund. RefundType must be "Full" or "Partial". For partial refunds, Amount is required.
type RefundTransactionResponse ¶
type RefundTransactionResponse struct {
GatewayRef string `json:"gateway_ref"`
TransactionRef string `json:"transaction_ref"`
RefundStatus string `json:"refund_status"`
AmountRefunded int64 `json:"amount_refunded"`
}
RefundTransactionResponse is the Data payload returned by RefundTransaction.
type SMSResponse ¶
type SMSResponse struct {
TransactionRef string `json:"transaction_ref"`
Status string `json:"status"`
Recipients []string `json:"recipients"`
MessageID string `json:"message_id"`
}
SMSResponse is returned by SendSMS.
type SendSMSParams ¶
type SendSMSParams struct {
To []string `json:"to"`
From string `json:"from"`
Body string `json:"body"`
TransactionRef string `json:"transaction_ref"`
}
SendSMSParams holds parameters for sending an SMS to one or more recipients.
type SimulateResponse ¶
type SimulateResponse struct {
TransactionRef string `json:"transaction_ref"`
Status string `json:"status"`
}
SimulateResponse is returned by Simulate.
type SimulateVirtualAccountParams ¶
type SimulateVirtualAccountParams struct {
VirtualAccountNumber string `json:"virtual_account_number"`
Amount float64 `json:"amount"`
}
SimulateVirtualAccountParams holds parameters for a sandbox credit simulation.
type SubMerchant ¶
type SubMerchant struct {
ID string `json:"id"`
MerchantID string `json:"merchant_id"`
DisplayName string `json:"display_name"`
AccountName string `json:"account_name"`
AccountNumber string `json:"account_number"`
BankCode string `json:"bank_code"`
BankName string `json:"bank_name"`
Email string `json:"email"`
Status string `json:"status"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
SubMerchant represents a sub-merchant account under an aggregator.
type SubMerchantListParams ¶
type SubMerchantListParams struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
SubMerchantListParams holds pagination parameters for listing sub-merchants.
type SubMerchantListResponse ¶
type SubMerchantListResponse struct {
Merchants []SubMerchant `json:"merchants"`
Total int `json:"total"`
Page int `json:"page"`
PerPage int `json:"per_page"`
}
SubMerchantListResponse holds a paginated list of sub-merchants.
type SubMerchantService ¶
type SubMerchantService struct {
// contains filtered or unexported fields
}
SubMerchantService manages sub-merchant accounts for aggregators and marketplace platforms. Requires an aggregator-level Squad account with the appropriate permissions.
func (*SubMerchantService) All ¶
func (s *SubMerchantService) All(ctx context.Context, params *SubMerchantListParams) *Iter[SubMerchant]
All returns a lazy iterator over all sub-merchants, fetching pages on demand.
iter := client.SubMerchants.All(ctx, nil)
for iter.Next() {
fmt.Println(iter.Item().DisplayName)
}
func (*SubMerchantService) Create ¶
func (s *SubMerchantService) Create(ctx context.Context, params *CreateSubMerchantParams) (*SubMerchant, error)
Create onboards a new sub-merchant under the aggregator account. The sub-merchant receives their own merchant ID and dashboard access.
func (*SubMerchantService) Delete ¶
func (s *SubMerchantService) Delete(ctx context.Context, merchantID string) (*DeleteSubMerchantResponse, error)
Delete removes a sub-merchant from the aggregator account.
func (*SubMerchantService) Get ¶
func (s *SubMerchantService) Get(ctx context.Context, merchantID string) (*SubMerchant, error)
Get retrieves the details of a sub-merchant by their merchant ID.
func (*SubMerchantService) List ¶
func (s *SubMerchantService) List(ctx context.Context, params *SubMerchantListParams) (*SubMerchantListResponse, error)
List returns a paginated list of all sub-merchants under the aggregator account.
type TransactionService ¶
type TransactionService struct {
// contains filtered or unexported fields
}
TransactionService handles payment initiation, verification, and refunds.
func (*TransactionService) AllMissedWebhooks ¶
func (s *TransactionService) AllMissedWebhooks(ctx context.Context, params *MissedWebhookParams) *Iter[VerifyTransactionResponse]
AllMissedWebhooks returns a lazy iterator over all missed webhook transactions.
iter := client.Transactions.AllMissedWebhooks(ctx, nil)
for iter.Next() {
tx := iter.Item()
fmt.Println(tx.TransactionRef, tx.Status)
}
func (*TransactionService) GetMissedWebhookTransactions ¶
func (s *TransactionService) GetMissedWebhookTransactions(ctx context.Context, params *MissedWebhookParams) (*MissedWebhookResponse, error)
GetMissedWebhookTransactions retrieves transactions whose webhooks were not delivered. Use for reconciliation. Delete processed entries to prevent re-delivery.
func (*TransactionService) GetUSSDbanks ¶
func (s *TransactionService) GetUSSDbanks(ctx context.Context) (*USSDbanksResponse, error)
GetUSSDbanks returns the list of banks that support USSD payment collection.
func (*TransactionService) InitiatePayment ¶
func (s *TransactionService) InitiatePayment(ctx context.Context, params *InitiatePaymentParams) (*InitiatePaymentResponse, error)
InitiatePayment creates a new payment transaction and returns a checkout URL. Redirect the end-user to Response.CheckoutURL to complete payment via the Squad modal.
func (*TransactionService) RefundTransaction ¶
func (s *TransactionService) RefundTransaction(ctx context.Context, params *RefundTransactionParams) (*RefundTransactionResponse, error)
RefundTransaction initiates a full or partial refund for a completed transaction. Set params.RefundType to "Full" or "Partial". Partial refunds require params.Amount.
func (*TransactionService) VerifyTransaction ¶
func (s *TransactionService) VerifyTransaction(ctx context.Context, transactionRef string) (*VerifyTransactionResponse, error)
VerifyTransaction retrieves the current status of a transaction by its reference. Call this after the user returns from the checkout URL or inside a webhook handler.
type TransferListParams ¶
type TransferListParams struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
StartDate string `json:"start_date,omitempty"`
EndDate string `json:"end_date,omitempty"`
Status string `json:"status,omitempty"` // "Success", "Processing", "Failed"
}
TransferListParams holds pagination and filter parameters for listing transfers.
type TransferListResponse ¶
type TransferListResponse struct {
Transfers []TransferStatusResponse `json:"transfers"`
Total int `json:"total"`
Page int `json:"page"`
PerPage int `json:"per_page"`
}
TransferListResponse holds a paginated list of transfer records.
type TransferResponse ¶
type TransferResponse struct {
TransactionRef string `json:"transaction_reference"`
Amount int64 `json:"amount"`
Fee float64 `json:"transaction_charge"`
Status string `json:"status"`
AccountName string `json:"account_name"`
AccountNumber string `json:"account_number"`
BankCode string `json:"bank_code"`
BankName string `json:"bank_name"`
CreatedAt string `json:"created_at"`
}
TransferResponse is the Data payload returned by both FundsTransfer and IntraTransfer.
type TransferService ¶
type TransferService struct {
// contains filtered or unexported fields
}
TransferService handles fund transfers to Nigerian bank accounts and Squad wallets.
func (*TransferService) AccountLookup ¶
func (s *TransferService) AccountLookup(ctx context.Context, bankCode, accountNumber string) (*AccountLookupResponse, error)
AccountLookup verifies a bank account number and returns the account holder's name. Always call this before FundsTransfer to validate the destination account.
func (*TransferService) All ¶
func (s *TransferService) All(ctx context.Context, params *TransferListParams) *Iter[TransferStatusResponse]
All returns a lazy iterator over all transfer transactions, fetching pages on demand. Filters from params (StartDate, EndDate, Status) are preserved across pages.
iter := client.Transfers.All(ctx, &squad.TransferListParams{Status: "Success"})
for iter.Next() {
fmt.Println(iter.Item().TransactionRef, squad.FromKobo(iter.Item().Amount))
}
func (*TransferService) FundsTransfer ¶
func (s *TransferService) FundsTransfer(ctx context.Context, params *FundsTransferParams) (*TransferResponse, error)
FundsTransfer transfers funds from the Squad merchant wallet to any Nigerian bank account. Use AccountLookup first to verify the destination account before transferring.
func (*TransferService) GetAllTransactions ¶
func (s *TransferService) GetAllTransactions(ctx context.Context, params *TransferListParams) (*TransferListResponse, error)
GetAllTransactions returns a paginated list of all transfer transactions.
func (*TransferService) GetTransactionStatus ¶
func (s *TransferService) GetTransactionStatus(ctx context.Context, transactionRef string) (*TransferStatusResponse, error)
GetTransactionStatus retrieves the current status of a previously initiated transfer.
func (*TransferService) IntraTransfer ¶
func (s *TransferService) IntraTransfer(ctx context.Context, params *IntraTransferParams) (*TransferResponse, error)
IntraTransfer transfers funds between two Squad wallet holders.
type TransferStatusResponse ¶
type TransferStatusResponse struct {
TransactionRef string `json:"transaction_ref"`
Status string `json:"status"`
Amount int64 `json:"amount"`
Fee float64 `json:"fee"`
ResponseCode string `json:"response_code"`
ResponseMessage string `json:"response_message"`
UpdatedAt string `json:"updated_at"`
}
TransferStatusResponse is returned by GetTransactionStatus.
type USSDBank ¶
type USSDBank struct {
BankCode string `json:"bank_code"`
BankName string `json:"bank_name"`
USSD string `json:"ussd"`
}
USSDBank describes a single bank supporting USSD payments.
type USSDbanksResponse ¶
type USSDbanksResponse struct {
Banks []USSDBank `json:"banks"`
}
USSDbanksResponse is the Data payload returned by GetUSSDbanks.
type UpdateVirtualAccountParams ¶
type UpdateVirtualAccountParams struct {
CustomerIdentifier string `json:"customer_identifier"`
BVN string `json:"bvn,omitempty"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
MiddleName string `json:"middle_name,omitempty"`
MobileNum string `json:"mobile_num,omitempty"`
}
UpdateVirtualAccountParams holds fields that can be modified on an existing virtual account.
type VASService ¶
type VASService struct {
// contains filtered or unexported fields
}
VASService handles value-added services: airtime, data, cable TV, electricity, and SMS. All purchases are charged from the Squad merchant wallet.
func (*VASService) BuyAirtime ¶
func (s *VASService) BuyAirtime(ctx context.Context, params *BuyAirtimeParams) (*VASTransactionResponse, error)
BuyAirtime purchases airtime and credits the specified phone number. Minimum purchase amount is 50 NGN. Supported networks: MTN, AIRTEL, GLO, 9MOBILE.
func (*VASService) BuyCable ¶
func (s *VASService) BuyCable(ctx context.Context, params *BuyCableParams) (*VASTransactionResponse, error)
BuyCable subscribes to a cable TV package for a smart card number. Use GetCablePackages to retrieve valid package codes before calling this.
func (*VASService) BuyData ¶
func (s *VASService) BuyData(ctx context.Context, params *BuyDataParams) (*VASTransactionResponse, error)
BuyData purchases a data bundle for a phone number. Use GetDataPlans to retrieve valid plan codes before calling this.
func (*VASService) BuyElectricity ¶
func (s *VASService) BuyElectricity(ctx context.Context, params *BuyElectricityParams) (*ElectricityResponse, error)
BuyElectricity purchases electricity units for a prepaid or postpaid meter. The returned ElectricityToken must be entered into the customer's meter.
func (*VASService) GetCablePackages ¶
func (s *VASService) GetCablePackages(ctx context.Context, cableProvider string) (*CablePackagesResponse, error)
GetCablePackages retrieves available cable TV subscription packages for the given provider. cableProvider is one of: "DSTV", "GOTV", "STARTIMES".
func (*VASService) GetDataPlans ¶
func (s *VASService) GetDataPlans(ctx context.Context, networkProvider string) (*DataPlansResponse, error)
GetDataPlans retrieves available data bundle plans for the given network provider. networkProvider is one of: "MTN", "AIRTEL", "GLO", "9MOBILE".
func (*VASService) GetElectricityBillers ¶
func (s *VASService) GetElectricityBillers(ctx context.Context) (*ElectricityBillersResponse, error)
GetElectricityBillers retrieves the list of available electricity distribution companies (DISCOs).
func (*VASService) SendSMS ¶
func (s *VASService) SendSMS(ctx context.Context, params *SendSMSParams) (*SMSResponse, error)
SendSMS sends a personalised SMS message to one or more recipients.
type VASTransactionResponse ¶
type VASTransactionResponse struct {
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"amount"`
Status string `json:"status"`
PhoneNumber string `json:"phone_number,omitempty"`
Network string `json:"network,omitempty"`
CreatedAt string `json:"created_at"`
}
VASTransactionResponse is the common response for airtime, data, and cable purchases.
type VerifyTransactionResponse ¶
type VerifyTransactionResponse struct {
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"transaction_amount"`
Fee float64 `json:"fee"`
MerchantAmount int64 `json:"merchant_amount"`
Status string `json:"transaction_status"`
Currency string `json:"transaction_currency_id"`
Email string `json:"email"`
TransactionType string `json:"transaction_type"`
MerchantName string `json:"merchant_name"`
MerchantEmail string `json:"merchant_email"`
Meta map[string]any `json:"meta,omitempty"`
IsRecurring bool `json:"is_recurring"`
ChargeToken *ChargeToken `json:"charge_token,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
VerifyTransactionResponse is the Data payload returned by VerifyTransaction.
type VirtualAccount ¶
type VirtualAccount struct {
VirtualAccountNumber string `json:"virtual_account_number"`
CustomerIdentifier string `json:"customer_identifier"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
MiddleName string `json:"middle_name"`
MobileNum string `json:"mobile_num"`
Email string `json:"email"`
UniqueID string `json:"unique_id"`
BeneficiaryAccount string `json:"beneficiary_account"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
VirtualAccount is the core virtual account object returned by the API.
type VirtualAccountService ¶
type VirtualAccountService struct {
// contains filtered or unexported fields
}
VirtualAccountService handles NUBAN virtual account creation and management.
func (*VirtualAccountService) AllTransactions ¶
func (s *VirtualAccountService) AllTransactions(ctx context.Context, customerIdentifier string, params *VirtualAccountTxParams) *Iter[VirtualAccountTransaction]
AllTransactions returns a lazy iterator over all transactions for a virtual account. Filters from params (StartDate, EndDate, Action) are preserved across pages.
iter := client.VirtualAccounts.AllTransactions(ctx, "cust-001", nil)
for iter.Next() {
tx := iter.Item()
fmt.Println(tx.TransactionRef, tx.SenderName)
}
func (*VirtualAccountService) Create ¶
func (s *VirtualAccountService) Create(ctx context.Context, params *CreateVirtualAccountParams) (*VirtualAccount, error)
Create creates a NUBAN-compliant virtual account for a customer. The account is permanently tied to CustomerIdentifier and receives payments on their behalf. CBN profiling must be completed on the Squad dashboard before calling this endpoint.
func (*VirtualAccountService) GetTransactions ¶
func (s *VirtualAccountService) GetTransactions(ctx context.Context, customerIdentifier string, params *VirtualAccountTxParams) (*VirtualAccountTxResponse, error)
GetTransactions retrieves paginated transactions for a virtual account by customer identifier.
func (*VirtualAccountService) Query ¶
func (s *VirtualAccountService) Query(ctx context.Context, virtualAccountNumber string) (*VirtualAccount, error)
Query retrieves the details of a virtual account by its account number.
func (*VirtualAccountService) Simulate ¶
func (s *VirtualAccountService) Simulate(ctx context.Context, params *SimulateVirtualAccountParams) (*SimulateResponse, error)
Simulate credits a sandbox virtual account with a test transaction. This method returns an error when called against a production base URL.
func (*VirtualAccountService) Update ¶
func (s *VirtualAccountService) Update(ctx context.Context, params *UpdateVirtualAccountParams) (*VirtualAccount, error)
Update modifies metadata on an existing virtual account.
type VirtualAccountTransaction ¶
type VirtualAccountTransaction struct {
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
SenderName string `json:"sender_name"`
SenderBank string `json:"sender_bank"`
SenderAccountNumber string `json:"sender_account_number"`
Status string `json:"transaction_status"`
CreatedAt string `json:"created_at"`
}
VirtualAccountTransaction is a single credit transaction on a virtual account.
type VirtualAccountTxParams ¶
type VirtualAccountTxParams struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
StartDate string `json:"start_date,omitempty"` // "YYYY-MM-DD"
EndDate string `json:"end_date,omitempty"`
Action string `json:"action,omitempty"`
}
VirtualAccountTxParams holds query parameters for fetching virtual account transactions.
type VirtualAccountTxResponse ¶
type VirtualAccountTxResponse struct {
Transactions []VirtualAccountTransaction `json:"transactions"`
Total int `json:"total"`
Page int `json:"page"`
PerPage int `json:"per_page"`
}
VirtualAccountTxResponse holds paginated transactions for a virtual account.
type WebhookDisputeBody ¶
type WebhookDisputeBody struct {
TicketID string `json:"ticket_id"`
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"amount"`
Status string `json:"dispute_status"`
Reason string `json:"dispute_reason"`
CreatedAt string `json:"created_at"`
}
WebhookDisputeBody holds the body payload for dispute events.
type WebhookEvent ¶
type WebhookEvent struct {
Event EventType `json:"Event"`
TransactionRef string `json:"TransactionRef"`
Body json.RawMessage `json:"Body"`
}
WebhookEvent is the top-level structure of all Squad webhook payloads. Squad uses PascalCase field names at the top level. Use event.Event to determine the event type, then call ParseBody() to decode the body.
func ParseWebhook ¶
func ParseWebhook(payload []byte, signature string, secret string) (*WebhookEvent, error)
ParseWebhook parses and validates an inbound Squad webhook.
payload is the raw HTTP request body bytes. signature is the value of the "x-squad-encrypted-body" HTTP header. secret is the merchant's Squad secret key (same key used for API calls).
Note: Squad sandbox does not send the signature header. Pass an empty string to skip signature validation during development (production always signs).
Returns ErrInvalidSignature if the HMAC-SHA512 signature does not match. Returns a parse error if the JSON payload is malformed.
func (*WebhookEvent) ParseBody ¶
func (e *WebhookEvent) ParseBody() (any, error)
ParseBody decodes the Body field into the appropriate typed struct based on Event. Returns one of:
- *WebhookTransactionBody for EventTransactionSuccess / EventTransactionFailed
- *WebhookVirtualAccountBody for EventVirtualAccountCredit
- *WebhookTransferBody for EventTransferSuccess / EventTransferFailed / EventTransferReversed
- *WebhookDisputeBody for EventDisputeOpened / EventDisputeResolved
- json.RawMessage for unknown or future event types
type WebhookRouter ¶
type WebhookRouter struct {
// contains filtered or unexported fields
}
WebhookRouter is an http.Handler that validates Squad webhook signatures and dispatches each event to its registered typed handler function.
Register handlers with the fluent On* methods, then mount the router as an HTTP handler:
router := squad.NewWebhookRouter(os.Getenv("SQUAD_SECRET_KEY")).
OnTransactionSuccess(handlePayment).
OnVirtualAccountCredit(handleCredit).
OnDisputeOpened(handleDispute)
http.Handle("/webhook/squad", router)
func NewWebhookRouter ¶
func NewWebhookRouter(secret string) *WebhookRouter
NewWebhookRouter creates a new WebhookRouter that validates signatures using secret. secret is the same Squad secret key used to initialise the Client.
func (*WebhookRouter) OnDisputeOpened ¶
func (r *WebhookRouter) OnDisputeOpened(fn func(context.Context, *WebhookDisputeBody) error) *WebhookRouter
OnDisputeOpened registers a handler for dispute.opened events.
func (*WebhookRouter) OnDisputeResolved ¶
func (r *WebhookRouter) OnDisputeResolved(fn func(context.Context, *WebhookDisputeBody) error) *WebhookRouter
OnDisputeResolved registers a handler for dispute.resolved events.
func (*WebhookRouter) OnError ¶
func (r *WebhookRouter) OnError(fn func(http.ResponseWriter, *http.Request, error)) *WebhookRouter
OnError registers a custom error handler called when signature validation fails, JSON parsing fails, or a dispatched handler returns an error. The default behaviour is to write an HTTP 400 or 403 response.
func (*WebhookRouter) OnTransactionFailed ¶
func (r *WebhookRouter) OnTransactionFailed(fn func(context.Context, *WebhookTransactionBody) error) *WebhookRouter
OnTransactionFailed registers a handler for charge.failed events.
func (*WebhookRouter) OnTransactionSuccess ¶
func (r *WebhookRouter) OnTransactionSuccess(fn func(context.Context, *WebhookTransactionBody) error) *WebhookRouter
OnTransactionSuccess registers a handler for charge.success events.
func (*WebhookRouter) OnTransferFailed ¶
func (r *WebhookRouter) OnTransferFailed(fn func(context.Context, *WebhookTransferBody) error) *WebhookRouter
OnTransferFailed registers a handler for transfer.failed events.
func (*WebhookRouter) OnTransferReversed ¶
func (r *WebhookRouter) OnTransferReversed(fn func(context.Context, *WebhookTransferBody) error) *WebhookRouter
OnTransferReversed registers a handler for transfer.reversed events.
func (*WebhookRouter) OnTransferSuccess ¶
func (r *WebhookRouter) OnTransferSuccess(fn func(context.Context, *WebhookTransferBody) error) *WebhookRouter
OnTransferSuccess registers a handler for transfer.success events.
func (*WebhookRouter) OnUnknown ¶
func (r *WebhookRouter) OnUnknown(fn func(context.Context, *WebhookEvent) error) *WebhookRouter
OnUnknown registers a fallback handler for unrecognised or future event types. The raw *WebhookEvent is passed so the caller can inspect event.Body directly.
func (*WebhookRouter) OnVirtualAccountCredit ¶
func (r *WebhookRouter) OnVirtualAccountCredit(fn func(context.Context, *WebhookVirtualAccountBody) error) *WebhookRouter
OnVirtualAccountCredit registers a handler for virtual-account.credit events.
func (*WebhookRouter) ServeHTTP ¶
func (r *WebhookRouter) ServeHTTP(w http.ResponseWriter, req *http.Request)
ServeHTTP implements http.Handler. It reads the request body, validates the x-squad-signature header, parses the event, and dispatches to the registered handler. Returns 403 on invalid signature, 400 on parse errors, 500 if a handler returns an error, and 200 on success.
type WebhookTransactionBody ¶
type WebhookTransactionBody struct {
TransactionRef string `json:"transaction_ref"`
GatewayRef string `json:"gateway_ref"`
Amount int64 `json:"amount"`
MerchantAmount int64 `json:"merchant_amount"`
Currency string `json:"currency"`
Status string `json:"transaction_status"`
Channel string `json:"transaction_type"` // "Card", "Bank", "Ussd", "MerchantUssd"
Email string `json:"email"`
CustomerName string `json:"customer_name,omitempty"`
MerchantID string `json:"merchant_id"`
Meta map[string]any `json:"meta,omitempty"`
IsRecurring bool `json:"is_recurring"`
ChargeToken *ChargeToken `json:"charge_token,omitempty"`
CreatedAt string `json:"created_at"`
}
WebhookTransactionBody holds the body payload for charge_successful and charge_failed events.
type WebhookTransferBody ¶
type WebhookTransferBody struct {
TransactionRef string `json:"transaction_ref"`
Amount int64 `json:"amount"`
Status string `json:"status"`
AccountName string `json:"account_name"`
AccountNumber string `json:"account_number"`
BankCode string `json:"bank_code"`
CreatedAt string `json:"created_at"`
}
WebhookTransferBody holds the body payload for transfer events.
type WebhookVirtualAccountBody ¶
type WebhookVirtualAccountBody struct {
VirtualAccountNumber string `json:"virtual_account_number"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
SenderName string `json:"sender_name"`
SenderBank string `json:"sender_bank"`
TransactionRef string `json:"transaction_ref"`
CustomerIdentifier string `json:"customer_identifier"`
CreatedAt string `json:"created_at"`
}
WebhookVirtualAccountBody holds the body payload for virtualaccount_credited events.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
payment
command
Package main demonstrates Squad payment initiation and verification.
|
Package main demonstrates Squad payment initiation and verification. |
|
virtualaccount
command
Package main demonstrates Squad virtual account creation and management.
|
Package main demonstrates Squad virtual account creation and management. |
|
webhook
command
Package main demonstrates Squad webhook signature validation and event routing.
|
Package main demonstrates Squad webhook signature validation and event routing. |
|
Package squadtest provides a mock Squad API server for use in tests.
|
Package squadtest provides a mock Squad API server for use in tests. |