sabi

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 26, 2026 License: MIT Imports: 17 Imported by: 0

README

sabi-go

The official Go client for the Sabi payment gateway. Standard library only; Go 1.22+.

go get github.com/YosefAshenafi/sabi-go@latest
import sabi "github.com/YosefAshenafi/sabi-go"

client := sabi.New(os.Getenv("SABI_BASE_URL"), os.Getenv("SABI_API_KEY"),
    sabi.WithUserAgent("myapp/1.0"))

payment, err := client.CreatePayment(ctx, sabi.CreatePaymentParams{
    Amount: "250.00", Currency: "ETB",
    ExternalReference: order.ID,          // idempotency key: a retry never charges twice
    Narrative: "Order " + order.Number,
    ReturnURL: "https://shop.example.et/orders/" + order.ID,
})
// send the payer to payment.CheckoutURL

Receive callbacks with the verifying handler. It refuses anything unsigned, tampered with, or more than five minutes old:

mux.Handle("POST /webhooks/sabi", sabi.WebhookHandler(os.Getenv("SABI_CALLBACK_SECRET"),
    func(ctx context.Context, cb *sabi.Callback) error {
        switch cb.Event {
        case sabi.EventCollectionSettled:
            p, err := client.GetPayment(ctx, cb.SabiReference) // confirm before acting
            if err != nil {
                return err // 500: Sabi retries later
            }
            return orders.MarkPaid(ctx, cb.DeliveryID, p)
        }
        return nil // 2xx for every event you do not handle
    }))
Area Methods
Payments CreatePayment, GetPayment, ListPayments, CancelPayment
Pay at a till by SMS code StartPaymentOTP, VerifyPaymentOTP, OTPAttemptsLeft
Refunds RefundPayment, ListRefunds
Payouts & transfers CreatePayout, GetPayout, ListPayouts, CreateTransfer, GetTransaction, ListTransactions
Account Account, Statement, QuoteFees, PaymentMethods
Callbacks CallbackURL, SetCallbackURL, ListCallbacks, TestCallback, ReplayCallback, VerifyCallback, WebhookHandler
Partners RegisterMerchant, GetMerchant, UpdateMerchantOwner, SetSettlementAccount, SettlementAccount
Native checkout CheckoutSession, Charge
Sandbox SimulatorSettle
Money ParseMinor("1250.50") == 125050, FormatMinor(125050) == "1250.50"

Errors are *sabi.Error (with Status, a stable Code, RequestID) or *sabi.NetworkError when no answer came back. sabi.IsTemporary, sabi.IsNotFound and sabi.ErrorCode classify them. Requests that are safe to repeat are retried with backoff, honouring Retry-After: every GET and every call that carries an external reference. After a NetworkError on a money call, look the transaction up by your external reference before raising it again.

Tests: go test ./... here for the client alone; the gateway's suite (../../run_tests.sh) also drives this SDK against a running Sabi.

License

MIT. See LICENSE.

Documentation

Overview

Package sabi is the official Go client for the Sabi payment gateway.

It covers the whole client API -- payments and the hosted checkout, refunds and cancellations, payouts, transfers, balances and statements, fee quotes, callback configuration and partner merchant onboarding -- and verifies the callbacks Sabi posts to your application.

It depends on nothing outside the standard library.

Collecting a payment

client := sabi.New("https://pay.example.et", os.Getenv("SABI_API_KEY"))

payment, err := client.CreatePayment(ctx, sabi.CreatePaymentParams{
	Amount:            "250.00",
	Currency:          "ETB",
	ExternalReference: order.ID, // your own id; repeating it never charges twice
	PayerName:         order.CustomerName,
	Narrative:         "Order " + order.Number,
	ReturnURL:         "https://shop.example.et/orders/" + order.ID,
})
if err != nil {
	return err
}
redirect(payment.CheckoutURL)

Hearing that it was paid

http.Handle("/webhooks/sabi", sabi.WebhookHandler(os.Getenv("SABI_CALLBACK_SECRET"),
	func(ctx context.Context, cb *sabi.Callback) error {
		if cb.Event != sabi.EventCollectionSettled {
			return nil // answer every event you do not handle with a 2xx
		}
		// A callback is a prompt: confirm with the API before acting.
		p, err := client.GetPayment(ctx, cb.SabiReference)
		if err != nil {
			return err // a non-2xx answer makes Sabi retry
		}
		return markPaid(ctx, cb.DeliveryID, p)
	}))

The handler refuses anything whose X-Sabi-Signature-V2 does not verify or is more than five minutes old, so a callback captured on the way cannot be replayed at you. Record DeliveryID and ignore a repeat: Sabi retries until your endpoint answers 2xx.

Errors

Every failure the API reports is an *Error carrying the HTTP status, a stable Code to branch on and the RequestID to quote to Sabi. Requests that are safe to repeat -- every GET, and every call that carries an external reference -- are retried on rate limiting and on temporary server and network failures, with backoff; nothing else is.

Index

Constants

View Source
const (
	CodeInvalidAPIKey         = "INVALID_API_KEY"
	CodeLiveModeNotActivated  = "LIVE_MODE_NOT_ACTIVATED"
	CodeClientSuspended       = "CLIENT_SUSPENDED"
	CodeValidationFailed      = "VALIDATION_FAILED"
	CodeInsufficientBalance   = "INSUFFICIENT_BALANCE"
	CodeNoSuchPayment         = "NO_SUCH_PAYMENT"
	CodeAlreadyPaid           = "ALREADY_PAID"
	CodeNotRefundable         = "NOT_REFUNDABLE"
	CodeRefundExceedsPayment  = "REFUND_EXCEEDS_PAYMENT"
	CodeNothingToRefund       = "NOTHING_TO_REFUND"
	CodePaymentInProgress     = "PAYMENT_IN_PROGRESS"
	CodeNotCancellable        = "NOT_CANCELLABLE"
	CodeRateLimited           = "RATE_LIMITED"
	CodeNotAPartner           = "NOT_A_PARTNER"
	CodeMerchantNotFound      = "MERCHANT_NOT_FOUND"
	CodePhoneInUse            = "PHONE_IN_USE"
	CodeEmailInUse            = "EMAIL_IN_USE"
	CodePrivateCallbackURL    = "PRIVATE_CALLBACK_URL"
	CodeInsecureCallbackURL   = "INSECURE_CALLBACK_URL"
	CodeDeliveryNotReplayable = "DELIVERY_NOT_REPLAYABLE"

	// Paying from a wallet on a one-time code (StartPaymentOTP and
	// VerifyPaymentOTP).
	CodeOTPNotAvailable  = "OTP_NOT_AVAILABLE"
	CodeMethodNotOffered = "METHOD_NOT_OFFERED"
	CodeInvalidAccount   = "INVALID_ACCOUNT"
	CodeNotPayable       = "NOT_PAYABLE"
	CodeExpired          = "EXPIRED"
	CodeTooManyCodes     = "TOO_MANY_CODES"
	CodeSMSUnavailable   = "SMS_UNAVAILABLE"
	CodeOTPNotRequested  = "OTP_NOT_REQUESTED"
	CodeOTPExpired       = "OTP_EXPIRED"
	CodeOTPInvalid       = "OTP_INVALID"
	CodeOTPLocked        = "OTP_LOCKED"
	CodeTooManyAttempts  = "TOO_MANY_ATTEMPTS"
)

Error codes an integration commonly branches on. The full list is in the API reference; any code not listed here is still returned in Error.Code.

View Source
const (
	StatusPending   = "pending"
	StatusSettled   = "settled"
	StatusFailed    = "failed"
	StatusExpired   = "expired"
	StatusCancelled = "cancelled"
)

Transaction statuses.

View Source
const (
	TypePayment       = "payment"
	TypeEscrowFunding = "escrow_funding"
	TypeBidBond       = "bid_bond"
	TypeDeposit       = "deposit"
	TypeWithdrawal    = "withdrawal"
	TypeEscrowRelease = "escrow_release"
	TypeRefund        = "refund"
	TypeTransfer      = "transfer"
)

Transaction types.

View Source
const (
	EventCollectionSettled = "collection.settled"
	EventCollectionFailed  = "collection.failed"
	EventPayoutPaid        = "payout.paid"
	EventPayoutFailed      = "payout.failed"
	EventTransferReceived  = "transfer.received"
	// EventPing is sent by TestCallback and nothing else.
	EventPing = "ping"

	// Optional events, sent only when chosen with SetCallback. Choosing the
	// refund events reports refunds by them instead of by payout.paid and
	// payout.failed.
	EventPaymentCancelled = "payment.cancelled"
	EventPaymentExpired   = "payment.expired"
	EventRefundSucceeded  = "refund.succeeded"
	EventRefundFailed     = "refund.failed"
	EventDisputeOpened    = "dispute.opened"
	EventDisputeWon       = "dispute.won"
	EventDisputeLost      = "dispute.lost"
	EventDisputeAccepted  = "dispute.accepted"
)

Callback events.

View Source
const (
	HeaderSignatureV2 = "X-Sabi-Signature-V2"
	HeaderTimestamp   = "X-Sabi-Timestamp"
	HeaderDelivery    = "X-Sabi-Delivery"
	HeaderEvent       = "X-Sabi-Event"
	// HeaderSignature is the older signature over the body alone. It can be
	// replayed, so VerifyCallback ignores it unless told otherwise.
	HeaderSignature = "X-Sabi-Signature"
)

Callback headers.

View Source
const DefaultTolerance = 5 * time.Minute

DefaultTolerance is how old a callback may be before it is refused.

View Source
const Version = "1.3.0"

Version is this client's version, sent in the User-Agent.

Variables

View Source
var (
	ErrMissingSignature = errors.New("sabi: the callback is not signed")
	ErrBadSignature     = errors.New("sabi: the callback signature does not match")
	ErrStaleCallback    = errors.New("sabi: the callback is too old or from the future")
)

Errors VerifyCallback returns.

View Source
var ErrInvalidAmount = errors.New("sabi: not a decimal amount with at most two decimal places")

ErrInvalidAmount is a decimal string that is not an amount of money.

Functions

func ErrorCode

func ErrorCode(err error) string

ErrorCode is the API error code of err, or "" when err is not one Sabi reported.

func FormatMinor

func FormatMinor(minor int64) string

FormatMinor turns minor units (125050) into the decimal string the API takes ("1250.50").

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether Sabi answered 404: no such object, or another client's, which Sabi reports the same way.

func IsTemporary

func IsTemporary(err error) bool

IsTemporary reports whether the same request may succeed later: a network failure, rate limiting, or a server-side failure. Validation errors, conflicts and authentication failures are not temporary.

func Mode

func Mode(apiKey string) string

Mode is what the key's prefix says about it: "live" for real money, "sandbox" for a merchant's test account. GET /v1/account says the same with authority; this is for checking configuration before any call.

func OTPAttemptsLeft added in v1.3.0

func OTPAttemptsLeft(err error) (left int, ok bool)

OTPAttemptsLeft is how many more codes may be tried after an OTP_INVALID answer from VerifyPaymentOTP. ok is false for any other error.

func ParseMinor

func ParseMinor(amount string) (int64, error)

ParseMinor turns a decimal amount such as "1250.50" into minor units (125050), exactly, with no floating point anywhere. Birr has two decimal places.

func WebhookHandler

func WebhookHandler(secret string, handle func(ctx context.Context, cb *Callback) error, opts ...VerifyOptions) http.Handler

WebhookHandler is an http.Handler for your callback URL. It verifies each callback and passes it to handle; an error from handle answers 500, which makes Sabi retry the delivery later. A callback that fails verification is answered 401 and never reaches handle.

Types

type Account

type Account struct {
	Client string `json:"client"`
	Name   string `json:"name"`
	// Mode is "live" or "test".
	Mode     string    `json:"mode"`
	Status   string    `json:"status"`
	Balances []Balance `json:"accounts"`
}

Account is who an API key belongs to and what it holds.

type AccountRule

type AccountRule struct {
	MinDigits int      `json:"min_digits"`
	MaxDigits int      `json:"max_digits"`
	Prefixes  []string `json:"prefixes,omitempty"`
	Luhn      bool     `json:"luhn,omitempty"`
	Example   string   `json:"example"`
}

AccountRule is what an account number on a channel looks like.

type Balance

type Balance struct {
	// Purpose is "settlement" (money collected for you) or "fee_income".
	Purpose  string `json:"purpose"`
	Currency string `json:"currency"`
	Balance  string `json:"balance"`
	// Held is what open disputes hold back and Available what can be paid
	// out now; settlement accounts only.
	Held      string `json:"held,omitempty"`
	Available string `json:"available,omitempty"`
}

Balance is one of a client's accounts.

type BlocklistEntry

type BlocklistEntry struct {
	ID string `json:"id"`
	// Attribute is "account", "ip" or "email".
	Attribute string    `json:"attribute"`
	Value     string    `json:"value"`
	Note      string    `json:"note,omitempty"`
	CreatedAt time.Time `json:"created_at"`
}

BlocklistEntry is a value refused on your traffic. Value is shown masked for an account; Sabi keeps it only as a keyed hash.

type BulkPayoutItem

type BulkPayoutItem struct {
	ExternalReference   string `json:"external_reference"`
	Amount              string `json:"amount"`
	BeneficiaryBankCode string `json:"beneficiary_bank_code"`
	BeneficiaryAccount  string `json:"beneficiary_account"`
	BeneficiaryName     string `json:"beneficiary_name"`
	Narrative           string `json:"narrative,omitempty"`
}

BulkPayoutItem is one payout of a batch.

type BulkPayoutParams

type BulkPayoutParams struct {
	Title string           `json:"title,omitempty"`
	Items []BulkPayoutItem `json:"items"`
}

BulkPayoutParams pays up to 500 people in one call. Each item's ExternalReference becomes its payout's, so sending the same list again pays nobody twice.

type Callback

type Callback struct {
	// DeliveryID is the same on every retry of one delivery: record it and
	// ignore a repeat.
	DeliveryID string `json:"-"`
	// Timestamp is when this attempt was signed.
	Timestamp time.Time `json:"-"`

	Event string `json:"event"`
	// Reference is your external reference (Sabi's when you gave none);
	// SabiReference is always Sabi's. ExternalReference repeats yours.
	Reference         string `json:"reference"`
	SabiReference     string `json:"sabi_reference"`
	ExternalReference string `json:"external_reference"`
	ProviderRef       string `json:"provider_ref"`
	Type              string `json:"type"`
	Status            string `json:"status"`
	Application       string `json:"application"`
	Currency          string `json:"currency"`
	// Amount is the principal, Net what reached the beneficiary, Total
	// what the payer was charged, FeeTotal every fee -- all decimal strings.
	Amount   string `json:"amount"`
	Net      string `json:"net"`
	FeeTotal string `json:"fee_total"`
	Total    string `json:"total"`
	// AmountMinor is the net of a collection or the principal of a payout,
	// in minor units. Prefer the decimal fields.
	AmountMinor   int64  `json:"amount_minor"`
	PayerName     string `json:"payer_name"`
	PayerBankCode string `json:"payer_bank_code"`
	// PayerAccount is the account the payer paid from; a card number is
	// only ever its first six and last four digits.
	PayerAccount  string `json:"payer_account"`
	FailureReason string `json:"failure_reason"`
	ValueDate     string `json:"value_date"`

	// Mode is "live" or "test": whether the money is real.
	Mode string `json:"mode"`
	// PaymentMethod is the channel a collection was paid with.
	PaymentMethod string `json:"payment_method"`
	// RefundOf is the payment a refund returns money from.
	RefundOf string `json:"refund_of"`
	// Dispute is set on the dispute.* events.
	Dispute *CallbackDispute `json:"dispute,omitempty"`
}

Callback is what Sabi posts to your callback URL.

func VerifyCallback

func VerifyCallback(secret string, header http.Header, body []byte, opts VerifyOptions) (*Callback, error)

VerifyCallback checks that body was sent by Sabi, under secret, recently, and decodes it. Call it with the raw bytes of the request body, before anything else reads them.

type CallbackConfig

type CallbackConfig struct {
	URL     string `json:"url"`
	Enabled bool   `json:"enabled"`
	// Events are the optional events you have chosen; CoreEvents are sent
	// to every client and OptionalEvents may be chosen.
	Events         []string `json:"events"`
	CoreEvents     []string `json:"core_events"`
	OptionalEvents []string `json:"optional_events"`
}

CallbackConfig is where callbacks are posted.

type CallbackDelivery

type CallbackDelivery struct {
	ID            string     `json:"id"`
	Event         string     `json:"event"`
	Status        string     `json:"status"`
	URL           string     `json:"url"`
	Attempts      int        `json:"attempts"`
	LastStatus    *int       `json:"last_status,omitempty"`
	LastError     string     `json:"last_error,omitempty"`
	NextAttemptAt *time.Time `json:"next_attempt_at,omitempty"`
	CreatedAt     time.Time  `json:"created_at"`
	UpdatedAt     time.Time  `json:"updated_at"`
}

CallbackDelivery is one attempt to notify you.

type CallbackDispute

type CallbackDispute struct {
	Reference string `json:"reference"`
	Reason    string `json:"reason"`
	Amount    string `json:"amount"`
	Status    string `json:"status"`
	RespondBy string `json:"respond_by"`
}

CallbackDispute is the dispute a dispute.* event is about. RespondBy is the RFC 3339 deadline for the merchant's evidence.

type CallbackTest

type CallbackTest struct {
	URL        string `json:"url"`
	Delivered  bool   `json:"delivered"`
	Status     *int   `json:"status,omitempty"`
	Error      string `json:"error,omitempty"`
	DurationMS int64  `json:"duration_ms"`
}

CallbackTest is how a test delivery went.

type ChargeResult

type ChargeResult struct {
	// Status is "succeeded" or "declined".
	Status        string          `json:"status"`
	Reference     string          `json:"reference"`
	ProviderRef   string          `json:"provider_ref,omitempty"`
	FailureReason string          `json:"failure_reason,omitempty"`
	Session       CheckoutSession `json:"session"`
}

ChargeResult is what the checkout made of a payer's attempt.

type CheckoutSession

type CheckoutSession struct {
	Reference string `json:"reference"`
	Narrative string `json:"narrative,omitempty"`
	PayingTo  string `json:"paying_to,omitempty"`
	PayerName string `json:"payer_name,omitempty"`
	Amount    string `json:"amount"`
	Lines     []struct {
		Label  string `json:"label"`
		Rate   string `json:"rate,omitempty"`
		Amount string `json:"amount"`
		Payer  string `json:"payer"`
	} `json:"lines"`
	Total     string          `json:"total"`
	Currency  string          `json:"currency"`
	Status    string          `json:"status"`
	Payable   bool            `json:"payable"`
	ExpiresAt time.Time       `json:"expires_at"`
	SettledAt *time.Time      `json:"settled_at,omitempty"`
	Simulated bool            `json:"simulated"`
	Channels  []PaymentMethod `json:"channels"`
	ReturnURL string          `json:"return_url,omitempty"`
}

CheckoutSession is what the hosted checkout shows a payer, for a native application drawing its own.

type Client

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

Client calls the Sabi API with one API key. It is safe for concurrent use.

func New

func New(baseURL, apiKey string, opts ...Option) *Client

New returns a client for the Sabi deployment at baseURL (such as https://pay.example.et), authenticating with apiKey.

func (*Client) Account

func (c *Client) Account(ctx context.Context) (*Account, error)

Account returns who the key belongs to, whether it moves real money, and its balances.

func (*Client) Block

func (c *Client) Block(ctx context.Context, attribute, value, note string) (*BlocklistEntry, error)

Block refuses an account, IP address or email on your traffic: a checkout attempt from it is declined and a withdrawal to it refused.

func (*Client) Blocklist

func (c *Client) Blocklist(ctx context.Context, limit, offset int) (*Page[BlocklistEntry], error)

Blocklist lists the values you have blocked, newest first, a page at a time.

func (*Client) CallbackURL

func (c *Client) CallbackURL(ctx context.Context) (*CallbackConfig, error)

CallbackURL returns where your callbacks are posted.

func (*Client) CancelPayment

func (c *Client) CancelPayment(ctx context.Context, reference, reason string) (*Transaction, error)

CancelPayment closes a payment nobody has paid, so its checkout stops taking money. Cancelling one already cancelled returns it unchanged.

func (*Client) Charge

func (c *Client) Charge(ctx context.Context, reference, channel, account, payerName string) (*ChargeResult, error)

Charge pays a payment at the checkout on the payer's behalf, from the channel and account they entered in your own form. Never retried: a charge is money leaving a person's account.

func (*Client) CheckoutSession

func (c *Client) CheckoutSession(ctx context.Context, reference string) (*CheckoutSession, error)

CheckoutSession returns what the hosted checkout would show the payer of a payment, for an application drawing its own checkout. It needs no API key: the payment reference is the payer's credential.

func (*Client) CloseVirtualAccount

func (c *Client) CloseVirtualAccount(ctx context.Context, id string) (*VirtualAccount, error)

CloseVirtualAccount stops a virtual account taking transfers.

func (*Client) CreateBulkPayout

func (c *Client) CreateBulkPayout(ctx context.Context, p BulkPayoutParams) (*PayoutBatch, error)

CreateBulkPayout pays a list in one call and returns the batch, row by row. It is safe to retry: every item is idempotent on its reference.

func (*Client) CreatePayment

func (c *Client) CreatePayment(ctx context.Context, p CreatePaymentParams) (*Transaction, error)

CreatePayment raises a collection and returns it with its fee breakdown and CheckoutURL. Repeating it with the same ExternalReference returns the same payment -- re-issued if it is still unpaid -- so it is retried safely.

func (*Client) CreatePayout

func (c *Client) CreatePayout(ctx context.Context, p CreatePayoutParams) (*Transaction, error)

CreatePayout sends money from your settlement balance to a bank account or wallet. Repeating it with the same ExternalReference never pays twice.

func (*Client) CreateSubaccount

func (c *Client) CreateSubaccount(ctx context.Context, p CreateSubaccountParams) (*Subaccount, error)

CreateSubaccount adds a partner that takes a share of the payments that name it.

func (*Client) CreateTransfer

func (c *Client) CreateTransfer(ctx context.Context, p CreateTransferParams) (*Transaction, error)

CreateTransfer moves money to another Sabi client, at once.

func (*Client) Currencies

func (c *Client) Currencies(ctx context.Context) ([]Currency, error)

Currencies lists the currencies Sabi holds and what each is used for.

func (*Client) DeactivateSubaccount

func (c *Client) DeactivateSubaccount(ctx context.Context, id string) (*Subaccount, error)

DeactivateSubaccount switches a partner off; it keeps what it was paid.

func (*Client) EmbedOrigins

func (c *Client) EmbedOrigins(ctx context.Context) (*EmbedOrigins, error)

EmbedOrigins returns the websites allowed to show your checkout in a pop-over with sabi.js.

func (*Client) GetMerchant

func (c *Client) GetMerchant(ctx context.Context, externalReference string) (*Merchant, error)

GetMerchant returns how one of your merchants stands.

func (*Client) GetPayment

func (c *Client) GetPayment(ctx context.Context, reference string) (*Transaction, error)

GetPayment returns one of your payments by Sabi's reference or yours.

func (*Client) GetPayout

func (c *Client) GetPayout(ctx context.Context, reference string) (*Transaction, error)

deciding the payout failed: it may have been accepted.

func (*Client) GetPayoutBatch

func (c *Client) GetPayoutBatch(ctx context.Context, id string) (*PayoutBatch, error)

GetPayoutBatch returns a bulk payout, with how each payout stands now.

func (*Client) GetSubaccount

func (c *Client) GetSubaccount(ctx context.Context, id string) (*Subaccount, error)

GetSubaccount returns one of your partners.

func (*Client) GetTransaction

func (c *Client) GetTransaction(ctx context.Context, reference string) (*Transaction, error)

GetTransaction returns one of your transactions of any kind.

func (*Client) ListAllRefunds

func (c *Client) ListAllRefunds(ctx context.Context, p ListParams) (*Page[Transaction], error)

ListAllRefunds lists every refund you have sent, whatever payment it was against, newest first.

func (*Client) ListCallbacks

func (c *Client) ListCallbacks(ctx context.Context, status string, limit, offset int) (*Page[CallbackDelivery], error)

ListCallbacks lists every attempt to notify you, newest first. status may be "", pending, delivered or dead.

func (*Client) ListPayments

func (c *Client) ListPayments(ctx context.Context, p ListParams) (*Page[Transaction], error)

ListPayments lists your collections, newest first.

func (*Client) ListPayouts

func (c *Client) ListPayouts(ctx context.Context, p ListParams) (*Page[Transaction], error)

ListPayouts lists money you have sent out, newest first.

func (*Client) ListRefunds

func (c *Client) ListRefunds(ctx context.Context, reference string) (*Refunds, error)

ListRefunds returns a payment's refunds and what is left to refund.

func (*Client) ListSubaccounts

func (c *Client) ListSubaccounts(ctx context.Context) ([]Subaccount, error)

ListSubaccounts lists your partners, newest first.

func (*Client) ListTransactions

func (c *Client) ListTransactions(ctx context.Context, p ListParams) (*Page[Transaction], error)

ListTransactions lists every kind of transaction, newest first.

func (*Client) ListVirtualAccounts

func (c *Client) ListVirtualAccounts(ctx context.Context, status string, limit, offset int) (*Page[VirtualAccount], error)

ListVirtualAccounts lists your virtual accounts, newest first. status may be "", active, expired or closed.

func (*Client) OpenVirtualAccount

func (c *Client) OpenVirtualAccount(ctx context.Context, p VirtualAccountParams) (*VirtualAccount, error)

OpenVirtualAccount opens a bank account number for one of your customers, or returns the one already open under the same external reference.

func (*Client) PaymentMethods

func (c *Client) PaymentMethods(ctx context.Context) ([]PaymentMethod, error)

PaymentMethods lists the channels payers can pay with and payouts can go to, with the rule each account number follows.

func (*Client) QuoteFees

func (c *Client) QuoteFees(ctx context.Context, p FeeQuoteParams) (*Quote, error)

QuoteFees prices a transaction without raising it.

func (*Client) Rate

func (c *Client) Rate(ctx context.Context, from, to, amount string) (*Rate, error)

Rate returns the rate between ETB and USD in the direction asked, and what amount (a decimal string, optional) becomes at it.

func (*Client) RefundPayment

func (c *Client) RefundPayment(ctx context.Context, reference string, p RefundParams) (*Transaction, error)

RefundPayment sends some or all of a paid payment back to the account the payer paid from. It returns the refund, a payout of type refund.

func (*Client) RegisterMerchant

func (c *Client) RegisterMerchant(ctx context.Context, p RegisterMerchantParams) (*RegisteredMerchant, error)

RegisterMerchant opens a Sabi merchant for a business your platform hosts and returns its credentials. Only a partner client may call it. Repeating it with the same ExternalReference returns the same merchant with freshly issued credentials.

func (*Client) ReplayCallback

func (c *Client) ReplayCallback(ctx context.Context, deliveryID string) (*CallbackDelivery, error)

ReplayCallback sends an abandoned delivery again.

func (*Client) SetCallback

func (c *Client) SetCallback(ctx context.Context, callbackURL string, events []string) (*CallbackConfig, error)

SetCallback sets where callbacks go and which optional events (the Event* constants from EventPaymentCancelled on) are sent there. A nil events keeps the ones chosen before; an empty slice chooses none.

func (*Client) SetCallbackURL

func (c *Client) SetCallbackURL(ctx context.Context, callbackURL string) (*CallbackConfig, error)

SetCallbackURL sets where your callbacks are posted; empty turns them off.

func (*Client) SetEmbedOrigins

func (c *Client) SetEmbedOrigins(ctx context.Context, origins []string) (*EmbedOrigins, error)

SetEmbedOrigins replaces those websites, as scheme://host[:port]; none switches embedding off.

func (*Client) SetSettlementAccount

func (c *Client) SetSettlementAccount(ctx context.Context, externalReference string, p SettlementAccountParams) (*MerchantSettlement, error)

SetSettlementAccount records where a merchant is paid.

func (*Client) SetSettlementSchedule

func (c *Client) SetSettlementSchedule(ctx context.Context, externalReference string, p SettlementScheduleParams) (*MerchantSettlement, error)

SetSettlementSchedule chooses when a merchant's live balance is paid to its settlement account: manual, daily, weekly or monthly.

func (*Client) SettlementAccount

func (c *Client) SettlementAccount(ctx context.Context, externalReference string) (*MerchantSettlement, error)

SettlementAccount returns where a merchant is paid.

func (*Client) SimulatorSettle

func (c *Client) SimulatorSettle(ctx context.Context, reference string) error

SimulatorSettle settles a pending payment or payout now. It exists only on a sandbox deployment, where no real money moves.

func (*Client) StartPaymentOTP added in v1.3.0

func (c *Client) StartPaymentOTP(ctx context.Context, reference string, p StartPaymentOTPInput) (*PaymentOTP, error)

StartPaymentOTP starts paying one of your pending payments straight from the payer's mobile-money wallet (telebirr, cbe_birr or mpesa): Sabi texts the payer a six-digit code, the payer reads it out, and you pass it to VerifyPaymentOTP. Asking again voids the earlier code. Never retried: each call texts the payer.

func (*Client) Statement

func (c *Client) Statement(ctx context.Context, day time.Time) (*Statement, error)

Statement returns every settled movement on your settlement account on one day (UTC), for reconciliation. A zero date means today.

func (*Client) TestCallback

func (c *Client) TestCallback(ctx context.Context) (*CallbackTest, error)

TestCallback sends a signed ping to your callback URL now and reports how your endpoint answered.

func (*Client) TransactionEvents

func (c *Client) TransactionEvents(ctx context.Context, reference string) (*Timeline, error)

TransactionEvents returns what has happened to one of your transactions: every attempt a payer made, settlement, refunds and callbacks.

func (*Client) Unblock

func (c *Client) Unblock(ctx context.Context, id string) error

Unblock takes one of your entries off the blocklist.

func (*Client) UpdateMerchantOwner

func (c *Client) UpdateMerchantOwner(ctx context.Context, externalReference string, p UpdateOwnerParams) (*Merchant, error)

UpdateMerchantOwner keeps the owner's sign-in in step with your platform.

func (*Client) VerifyPaymentOTP added in v1.3.0

func (c *Client) VerifyPaymentOTP(ctx context.Context, reference, code string) (*PaymentOTPResult, error)

VerifyPaymentOTP checks the code the payer read out and, when it is right, charges their wallet. A declined charge is not an error: the result's Charge.Status is "declined" and the payment stays pending. A wrong code is an *Error with Code OTP_INVALID (see OTPAttemptsLeft). Never retried: a charge is money leaving a person's account.

func (*Client) VirtualAccount

func (c *Client) VirtualAccount(ctx context.Context, id string) (*VirtualAccount, error)

VirtualAccount fetches one of your virtual accounts.

func (*Client) VirtualAccountDeposits

func (c *Client) VirtualAccountDeposits(ctx context.Context, id string, limit, offset int) (*Page[VirtualAccountDeposit], error)

VirtualAccountDeposits lists the transfers into a virtual account.

type CreatePaymentParams

type CreatePaymentParams struct {
	Amount   string `json:"amount"`
	Currency string `json:"currency"`
	// Type is payment (default), escrow_funding, bid_bond or deposit.
	Type        string `json:"type,omitempty"`
	Application string `json:"application,omitempty"`
	// ExternalReference is your own id for the payment and makes the call
	// idempotent. Required.
	ExternalReference string            `json:"external_reference"`
	PayerName         string            `json:"payer_name,omitempty"`
	Narrative         string            `json:"narrative,omitempty"`
	ExpiresAt         *time.Time        `json:"expires_at,omitempty"`
	ReturnURL         string            `json:"return_url,omitempty"`
	Metadata          map[string]string `json:"metadata,omitempty"`

	Customer      *Customer      `json:"customer,omitempty"`
	Customization *Customization `json:"customization,omitempty"`
	// LineItems must add up to Amount.
	LineItems []LineItem `json:"line_items,omitempty"`
	// PaymentMethods offers only these channel codes, in this order.
	PaymentMethods []string `json:"payment_methods,omitempty"`
	// CallbackURL sends this payment's callbacks here instead of to your
	// configured callback URL.
	CallbackURL string `json:"callback_url,omitempty"`
	// Subaccount names a partner that takes a share when the payment
	// settles.
	Subaccount *SubaccountSplit `json:"subaccount,omitempty"`
}

CreatePaymentParams raises a collection.

type CreatePayoutParams

type CreatePayoutParams struct {
	Amount   string `json:"amount"`
	Currency string `json:"currency"`
	// Type is withdrawal (default), escrow_release or refund.
	Type              string `json:"type,omitempty"`
	Application       string `json:"application,omitempty"`
	ExternalReference string `json:"external_reference"`
	Narrative         string `json:"narrative,omitempty"`
	// BeneficiaryBankCode is a payout channel from PaymentMethods.
	BeneficiaryBankCode string            `json:"beneficiary_bank_code,omitempty"`
	BeneficiaryAccount  string            `json:"beneficiary_account"`
	BeneficiaryName     string            `json:"beneficiary_name"`
	Metadata            map[string]string `json:"metadata,omitempty"`
}

CreatePayoutParams sends money from your balance to an account.

type CreateSubaccountParams

type CreateSubaccountParams struct {
	Name          string `json:"name"`
	Channel       string `json:"channel"`
	AccountNumber string `json:"account_number"`
	AccountName   string `json:"account_name"`
	SplitType     string `json:"split_type"`
	SplitValue    string `json:"split_value"`
}

CreateSubaccountParams adds a partner.

type CreateTransferParams

type CreateTransferParams struct {
	Amount            string            `json:"amount"`
	Currency          string            `json:"currency"`
	Destination       string            `json:"destination"`
	ExternalReference string            `json:"external_reference"`
	Narrative         string            `json:"narrative,omitempty"`
	Metadata          map[string]string `json:"metadata,omitempty"`
}

CreateTransferParams moves money to another Sabi client.

type Currency

type Currency struct {
	Code        string `json:"code"`
	Name        string `json:"name"`
	Decimals    int    `json:"decimals"`
	Collections bool   `json:"collections"`
	Payouts     bool   `json:"payouts"`
	Swaps       bool   `json:"swaps"`
}

Currency is one currency Sabi holds and what it can be used for.

type Customer

type Customer struct {
	Name        string `json:"name,omitempty"`
	FirstName   string `json:"first_name,omitempty"`
	LastName    string `json:"last_name,omitempty"`
	Email       string `json:"email,omitempty"`
	PhoneNumber string `json:"phone_number,omitempty"`
}

Customer describes who is paying.

type Customization

type Customization struct {
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
}

Customization is how the checkout presents a payment.

type EmbedOrigins

type EmbedOrigins struct {
	Origins []string `json:"origins"`
	Script  string   `json:"script"`
}

EmbedOrigins are the websites allowed to show your checkout in a pop-over, and the checkout script they load.

type Error

type Error struct {
	// Status is the HTTP status.
	Status int
	// Code is stable and part of the API contract: branch on it, never on
	// Message.
	Code    string
	Message string
	// Details carries field-level problems for a 422, under "fields".
	Details map[string]any
	// RequestID identifies the request in Sabi's logs; quote it to support.
	RequestID string
	// RetryAfter is how long Sabi asked the caller to wait, on a 429.
	RetryAfter time.Duration
}

Error is a failure the Sabi API reported.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Fields

func (e *Error) Fields() map[string]string

Fields are the field-level validation problems of a 422, by field name.

type Fee

type Fee struct {
	Label  string `json:"label"`
	Type   string `json:"type"`
	Rate   string `json:"rate"`
	Amount string `json:"amount"`
	// Payer is "customer" (added on top) or "recipient" (taken out).
	Payer string `json:"payer"`
	// Owner is who the fee is owed to: "sabi", "escrow" or "application".
	Owner string `json:"owner"`
}

Fee is one line of a transaction's authoritative fee breakdown.

type FeeQuoteParams

type FeeQuoteParams struct {
	Amount      string `json:"amount"`
	Currency    string `json:"currency"`
	Type        string `json:"type"`
	Application string `json:"application,omitempty"`
}

FeeQuoteParams asks what a transaction would cost.

type LineItem

type LineItem struct {
	Name       string `json:"name"`
	Quantity   int64  `json:"quantity,omitempty"`
	UnitAmount string `json:"unit_amount"`
	Amount     string `json:"amount,omitempty"`
}

LineItem is one line of what a payment is for. UnitAmount is a decimal string; Amount (in answers) is the line's total.

type ListParams

type ListParams struct {
	Status string
	Type   string
	// Direction applies to ListTransactions only: in, out or internal.
	Direction string
	// Search matches references, the narrative and the payer's name.
	Search string
	// From and To bound when the transaction was raised: From inclusive,
	// To exclusive.
	From, To time.Time
	Limit    int
	Offset   int
}

ListParams narrows and pages a listing. Zero values are left out.

type Merchant

type Merchant struct {
	MerchantNumber     int64              `json:"merchant_number"`
	ExternalReference  string             `json:"external_reference"`
	BusinessName       string             `json:"business_name"`
	VerificationStatus string             `json:"verification_status"`
	LiveStatus         string             `json:"live_status"`
	SignIn             MerchantSignIn     `json:"sign_in"`
	SettlementAccount  *SettlementAccount `json:"settlement_account"`
}

Merchant is how one of a partner's merchants stands.

type MerchantCredentials

type MerchantCredentials struct {
	Client         string `json:"client"`
	Status         string `json:"status"`
	APIKey         string `json:"api_key"`
	CallbackSecret string `json:"callback_secret"`
}

MerchantCredentials are one of a merchant's two clients.

type MerchantSettlement

type MerchantSettlement struct {
	MerchantNumber    int64              `json:"merchant_number"`
	ExternalReference string             `json:"external_reference"`
	SettlementAccount *SettlementAccount `json:"settlement_account"`
}

MerchantSettlement is a merchant's settlement account, which is nil when none has been set.

type MerchantSignIn

type MerchantSignIn struct {
	Phone    string `json:"phone"`
	Email    string `json:"email,omitempty"`
	Password bool   `json:"password"`
	URL      string `json:"url"`
}

MerchantSignIn is how a merchant's owner reaches the portal.

type NetworkError

type NetworkError struct{ Err error }

NetworkError is a request that got no answer from Sabi at all: the connection failed or timed out. Whether it was acted on is unknown, so a money call that fails this way must be looked up by its external reference before it is raised again.

func (*NetworkError) Error

func (e *NetworkError) Error() string

func (*NetworkError) Timeout

func (e *NetworkError) Timeout() bool

Timeout reports whether the request timed out.

func (*NetworkError) Unwrap

func (e *NetworkError) Unwrap() error

type Option

type Option func(*Client)

Option changes how a Client is built.

func WithHTTPClient

func WithHTTPClient(c *http.Client) Option

WithHTTPClient sends requests through c instead of a client with a 30-second timeout.

func WithMaxRetries

func WithMaxRetries(n int) Option

WithMaxRetries sets how many times a request that is safe to repeat is retried after a temporary failure. The default is 2; 0 turns retries off.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent names your application in the User-Agent Sabi logs, before this library's own name.

type Page

type Page[T any] struct {
	Data   []T `json:"data"`
	Total  int `json:"total"`
	Limit  int `json:"limit"`
	Offset int `json:"offset"`
}

Page is one page of a listing.

type PaymentMethod

type PaymentMethod struct {
	Code         string      `json:"code"`
	Name         string      `json:"name"`
	Kind         string      `json:"kind"`
	Collect      bool        `json:"collect"`
	Payout       bool        `json:"payout"`
	AccountLabel string      `json:"account_label"`
	AccountHint  string      `json:"account_hint"`
	Account      AccountRule `json:"account"`
}

PaymentMethod is a channel money can come in or go out through.

type PaymentOTP added in v1.3.0

type PaymentOTP struct {
	Reference     string `json:"reference"`
	Channel       string `json:"channel"`
	AccountMasked string `json:"account_masked"`
	// Amount is what the payer will be charged, fees included.
	Amount    string    `json:"amount"`
	Currency  string    `json:"currency"`
	ExpiresAt time.Time `json:"expires_at"`
	// StandInCode is the code itself, present only when the Sabi you are
	// talking to simulates SMS (development and test). Never set with a
	// real SMS provider.
	StandInCode string `json:"stand_in_code,omitempty"`
}

PaymentOTP is a code on its way to a payer's phone.

type PaymentOTPCharge added in v1.3.0

type PaymentOTPCharge struct {
	// Status is "succeeded" or "declined".
	Status        string `json:"status"`
	FailureReason string `json:"failure_reason,omitempty"`
}

PaymentOTPCharge is how the wallet answered.

func (PaymentOTPCharge) Succeeded added in v1.3.0

func (c PaymentOTPCharge) Succeeded() bool

Succeeded reports whether the payer's money was taken.

type PaymentOTPResult added in v1.3.0

type PaymentOTPResult struct {
	// Payment is the payment after the charge, as GetPayment returns it.
	Payment Transaction      `json:"payment"`
	Charge  PaymentOTPCharge `json:"charge"`
}

PaymentOTPResult is a verified code and the charge it authorised.

type PayoutBatch

type PayoutBatch struct {
	ID        string           `json:"id"`
	Title     string           `json:"title"`
	Status    string           `json:"status"`
	Currency  string           `json:"currency"`
	Items     int              `json:"items"`
	Valid     int              `json:"valid"`
	Sent      int              `json:"sent"`
	Failed    int              `json:"failed"`
	Total     string           `json:"total"`
	CreatedAt time.Time        `json:"created_at"`
	Rows      []PayoutBatchRow `json:"rows"`
}

PayoutBatch is a bulk payout, row by row.

type PayoutBatchRow

type PayoutBatchRow struct {
	Row                      int    `json:"row"`
	ExternalReference        string `json:"external_reference"`
	Status                   string `json:"status"`
	Error                    string `json:"error,omitempty"`
	Reference                string `json:"reference,omitempty"`
	PayoutStatus             string `json:"payout_status,omitempty"`
	Amount                   string `json:"amount"`
	BeneficiaryBankCode      string `json:"beneficiary_bank_code"`
	BeneficiaryName          string `json:"beneficiary_name"`
	BeneficiaryAccountMasked string `json:"beneficiary_account_masked"`
}

PayoutBatchRow is one item: invalid (never sent), failed (refused when sent), or sent, when PayoutStatus says how its payout stands.

type Quote

type Quote struct {
	Amount   string `json:"amount"`
	Currency string `json:"currency"`
	Type     string `json:"type"`
	Fees     []Fee  `json:"fees"`
	FeeTotal string `json:"fee_total"`
	Total    string `json:"total"`
	Net      string `json:"net"`
}

Quote is a fee breakdown for a transaction that has not been raised.

type Rate

type Rate struct {
	From      string `json:"from"`
	To        string `json:"to"`
	Rate      string `json:"rate"`
	Amount    string `json:"amount,omitempty"`
	Converted string `json:"converted,omitempty"`
	RateID    string `json:"rate_id"`
	SetAt     string `json:"set_at"`
}

Rate is the exchange rate a swap is priced at now.

type RefundParams

type RefundParams struct {
	// Amount is optional: left empty, everything still refundable.
	Amount            string `json:"amount,omitempty"`
	Currency          string `json:"currency,omitempty"`
	Reason            string `json:"reason,omitempty"`
	ExternalReference string `json:"external_reference"`
}

RefundParams sends money back to whoever paid a payment.

type Refunds

type Refunds struct {
	PaymentReference string        `json:"payment_reference"`
	Currency         string        `json:"currency"`
	Refunded         string        `json:"refunded"`
	Refundable       string        `json:"refundable"`
	Refunds          []Transaction `json:"refunds"`
}

Refunds is a payment's refunds, and what is left to refund.

type RegisterMerchantParams

type RegisterMerchantParams struct {
	ExternalReference string `json:"external_reference"`
	BusinessName      string `json:"business_name"`
	BusinessType      string `json:"business_type,omitempty"`
	OwnerName         string `json:"owner_name"`
	OwnerEmail        string `json:"owner_email"`
	OwnerPhone        string `json:"owner_phone"`
	// OwnerPasswordHash is the argon2id PHC hash of the owner's password on
	// your platform -- never the password.
	OwnerPasswordHash string `json:"owner_password_hash,omitempty"`
	CallbackURL       string `json:"callback_url,omitempty"`
}

RegisterMerchantParams opens a merchant for a business a partner hosts.

type RegisteredMerchant

type RegisteredMerchant struct {
	MerchantNumber     int64               `json:"merchant_number"`
	ExternalReference  string              `json:"external_reference"`
	BusinessName       string              `json:"business_name"`
	VerificationStatus string              `json:"verification_status"`
	Created            bool                `json:"created"`
	SignIn             MerchantSignIn      `json:"sign_in"`
	Test               MerchantCredentials `json:"test"`
	Live               MerchantCredentials `json:"live"`
}

RegisteredMerchant is a merchant with the credentials this call issued. They are shown once.

type SettlementAccount

type SettlementAccount struct {
	Channel     string     `json:"channel"`
	AccountHint string     `json:"account_hint"`
	HolderName  string     `json:"holder_name"`
	Verified    bool       `json:"verified"`
	VerifiedAt  *time.Time `json:"verified_at"`
	UpdatedAt   time.Time  `json:"updated_at"`
	// Schedule is when the merchant's live balance is paid to the account.
	Schedule SettlementSchedule `json:"schedule"`
}

SettlementAccount is where a merchant is paid, masked.

type SettlementAccountParams

type SettlementAccountParams struct {
	Channel       string `json:"channel"`
	AccountNumber string `json:"account_number"`
	HolderName    string `json:"holder_name"`
}

SettlementAccountParams is where a merchant is paid.

type SettlementSchedule

type SettlementSchedule struct {
	// Frequency is manual, daily, weekly or monthly.
	Frequency     string `json:"frequency"`
	Weekday       int    `json:"weekday"`
	DayOfMonth    int    `json:"day_of_month"`
	MinimumAmount string `json:"minimum_amount"`
	ReserveAmount string `json:"reserve_amount"`
	Description   string `json:"description"`
	// NextSettlementOn is YYYY-MM-DD, or nil when paid by hand only or the
	// account is not yet verified.
	NextSettlementOn *string `json:"next_settlement_on"`
}

SettlementSchedule is when a merchant's live balance is paid out.

type SettlementScheduleParams

type SettlementScheduleParams struct {
	Frequency     string `json:"frequency"`
	Weekday       int    `json:"weekday,omitempty"`
	DayOfMonth    int    `json:"day_of_month,omitempty"`
	MinimumAmount string `json:"minimum_amount,omitempty"`
	ReserveAmount string `json:"reserve_amount,omitempty"`
}

SettlementScheduleParams chooses when a merchant is paid. Weekday (1 Monday to 7 Sunday) is for weekly and DayOfMonth (1 to 31) for monthly.

type StartPaymentOTPInput added in v1.3.0

type StartPaymentOTPInput struct {
	// Channel is telebirr, cbe_birr or mpesa. Bank and card payments go
	// through the hosted checkout.
	Channel string `json:"channel"`
	// Account is the wallet's phone number, in any usual spelling.
	Account string `json:"account"`
}

StartPaymentOTPInput names the mobile-money wallet to charge.

type Statement

type Statement struct {
	Date  string          `json:"date"`
	Lines []StatementLine `json:"lines"`
}

Statement is every settled movement on your settlement account on one day.

type StatementLine

type StatementLine struct {
	ProviderRef string `json:"provider_ref"`
	// Direction is credit or debit, from your side.
	Direction    string    `json:"direction"`
	Amount       string    `json:"amount"`
	Currency     string    `json:"currency"`
	Reference    string    `json:"reference"`
	Narrative    string    `json:"narrative,omitempty"`
	Counterparty string    `json:"counterparty,omitempty"`
	ValueDate    time.Time `json:"value_date"`
}

StatementLine is one of them, as your reconciliation reads it.

type Subaccount

type Subaccount struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	Channel       string `json:"channel"`
	AccountMasked string `json:"account_masked"`
	AccountName   string `json:"account_name"`
	// SplitType is "percentage" (SplitValue "10.00" is 10%) or "flat".
	SplitType  string `json:"split_type"`
	SplitValue string `json:"split_value"`
	Currency   string `json:"currency"`
	Active     bool   `json:"active"`
	// Splits is how many payments have paid it a share, Shared how much.
	Splits    int       `json:"splits"`
	Shared    string    `json:"shared"`
	CreatedAt time.Time `json:"created_at"`
}

Subaccount is a partner that takes a share of the payments that name it.

type SubaccountSplit

type SubaccountSplit struct {
	ID         string `json:"id"`
	SplitType  string `json:"split_type,omitempty"`
	SplitValue string `json:"split_value,omitempty"`
}

SubaccountSplit names a partner on a payment, at its own split or, with SplitType and SplitValue, at one for this payment only.

type Timeline

type Timeline struct {
	Reference string          `json:"reference"`
	Status    string          `json:"status"`
	Events    []TimelineEvent `json:"events"`
}

Timeline is what has happened to one transaction, oldest first.

type TimelineEvent

type TimelineEvent struct {
	At      time.Time         `json:"at"`
	Event   string            `json:"event"`
	Summary string            `json:"summary"`
	Detail  map[string]string `json:"detail,omitempty"`
}

TimelineEvent is one step of it: created, attempt_succeeded, attempt_declined, settled, refunded, callback_delivered and so on.

type Transaction

type Transaction struct {
	// Reference is Sabi's own; ExternalReference is yours.
	Reference         string `json:"reference"`
	ExternalReference string `json:"external_reference,omitempty"`
	Type              string `json:"type"`
	Direction         string `json:"direction"`
	Status            string `json:"status"`
	Currency          string `json:"currency"`
	// Amount is the principal; Total is what the payer is charged (or what
	// leaves your balance, for a payout); Net is what the beneficiary
	// receives. FeeTotal is every fee, whoever bears it.
	Amount   string `json:"amount"`
	FeeTotal string `json:"fee_total"`
	Total    string `json:"total"`
	Net      string `json:"net"`
	Fees     []Fee  `json:"fees"`

	Narrative   string `json:"narrative,omitempty"`
	PayerName   string `json:"payer_name,omitempty"`
	Application string `json:"application,omitempty"`

	BeneficiaryName          string `json:"beneficiary_name,omitempty"`
	BeneficiaryAccountMasked string `json:"beneficiary_account_masked,omitempty"`

	// CheckoutURL is where the payer pays a collection.
	CheckoutURL string `json:"checkout_url,omitempty"`
	ProviderRef string `json:"provider_ref,omitempty"`

	FailureReason string     `json:"failure_reason,omitempty"`
	ExpiresAt     *time.Time `json:"expires_at,omitempty"`
	CreatedAt     time.Time  `json:"created_at"`
	SettledAt     *time.Time `json:"settled_at,omitempty"`

	Metadata map[string]string `json:"metadata,omitempty"`

	Title     string     `json:"title,omitempty"`
	Customer  *Customer  `json:"customer,omitempty"`
	LineItems []LineItem `json:"line_items,omitempty"`
	// PaymentMethods are the channels the checkout offers, when restricted.
	PaymentMethods []string `json:"payment_methods,omitempty"`
	// PaymentMethod is the channel that paid a settled payment, and
	// PayerAccountMasked the account it was paid from.
	PaymentMethod      string `json:"payment_method,omitempty"`
	PayerAccountMasked string `json:"payer_account_masked,omitempty"`
	// CallbackURL is where this transaction's callbacks go, when you set
	// one for it.
	CallbackURL string `json:"callback_url,omitempty"`
	// QRCodeURL is an SVG QR code of CheckoutURL, while the payment can be
	// made.
	QRCodeURL string `json:"qr_code_url,omitempty"`
}

Transaction is one movement of money: a payment (direction "in"), a payout or refund ("out") or a transfer ("internal").

func (*Transaction) Settled

func (t *Transaction) Settled() bool

Settled reports whether the money has moved.

type UpdateOwnerParams

type UpdateOwnerParams struct {
	OwnerName         *string `json:"owner_name,omitempty"`
	OwnerEmail        *string `json:"owner_email,omitempty"`
	OwnerPasswordHash *string `json:"owner_password_hash,omitempty"`
}

UpdateOwnerParams keeps the owner's sign-in in step with the partner's. A nil field is left as it is.

type VerifyOptions

type VerifyOptions struct {
	// Tolerance is how far a callback's timestamp may be from now; zero
	// means DefaultTolerance.
	Tolerance time.Duration
	// Now is the clock; nil means time.Now.
	Now func() time.Time
	// AllowLegacy accepts a callback that carries only the older body-only
	// signature, for a Sabi deployment that predates the V2 header. It
	// gives up replay protection; leave it off.
	AllowLegacy bool
}

VerifyOptions changes how a callback is checked.

type VirtualAccount

type VirtualAccount struct {
	ID                string `json:"id"`
	ExternalReference string `json:"external_reference"`
	AccountName       string `json:"account_name"`
	AccountNumber     string `json:"account_number"`
	BankCode          string `json:"bank_code"`
	BankName          string `json:"bank_name"`
	Currency          string `json:"currency"`
	// Status is active, expired or closed.
	Status         string            `json:"status"`
	ExpectedAmount *string           `json:"expected_amount"`
	SingleUse      bool              `json:"single_use"`
	ExpiresAt      *time.Time        `json:"expires_at"`
	ClosedAt       *time.Time        `json:"closed_at"`
	CustomerEmail  string            `json:"customer_email,omitempty"`
	CustomerPhone  string            `json:"customer_phone,omitempty"`
	Received       string            `json:"received"`
	Deposits       int               `json:"deposits"`
	Metadata       map[string]string `json:"metadata,omitempty"`
	CreatedAt      time.Time         `json:"created_at"`
}

VirtualAccount is a bank account number opened for one of your customers: transfers into it are credited to you as payments.

type VirtualAccountDeposit

type VirtualAccountDeposit struct {
	ID            string `json:"id"`
	BankReference string `json:"bank_reference"`
	Amount        string `json:"amount"`
	Currency      string `json:"currency"`
	PayerName     string `json:"payer_name,omitempty"`
	PayerChannel  string `json:"payer_channel,omitempty"`
	PayerAccount  string `json:"payer_account,omitempty"`
	// Status is credited, or refused for the bank to return.
	Status           string    `json:"status"`
	RefusalReason    string    `json:"refusal_reason,omitempty"`
	PaymentReference string    `json:"payment_reference,omitempty"`
	ReceivedAt       time.Time `json:"received_at"`
}

VirtualAccountDeposit is one transfer into a virtual account.

type VirtualAccountParams

type VirtualAccountParams struct {
	ExternalReference string            `json:"external_reference"`
	AccountName       string            `json:"account_name"`
	CustomerEmail     string            `json:"customer_email,omitempty"`
	CustomerPhone     string            `json:"customer_phone,omitempty"`
	ExpectedAmount    string            `json:"expected_amount,omitempty"`
	SingleUse         bool              `json:"single_use,omitempty"`
	ExpiresAt         *time.Time        `json:"expires_at,omitempty"`
	Metadata          map[string]string `json:"metadata,omitempty"`
}

VirtualAccountParams opens a virtual account. ExternalReference makes the call idempotent.

Jump to

Keyboard shortcuts

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