go_monobank

package module
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Mar 2, 2026 License: MIT Imports: 20 Imported by: 0

README

go-monobank

Go Reference Go Report Card

Minimal, production-focused Go SDK for monobank Acquiring API.

This library follows the same style as other stremovskyy/* SDKs:

  • simple public interface
  • fluent request builder
  • explicit typed errors
  • practical defaults for production

Features

  • Card tokenization (verification flow): POST /api/merchant/invoice/create
  • Payment by saved card token: POST /api/merchant/wallet/payment
  • Invoice status lookup: GET /api/merchant/invoice/status
  • PRRO fiscal checks by invoice: GET /api/merchant/invoice/fiscal-checks
  • Webhook parsing and signature verification (X-Sign, ECDSA SHA-256)
  • Structured API and transport errors with errors.Is(...) support
  • Business-level payment error helpers (PaymentError)
  • Dry-run mode for safe payload inspection
  • Built-in log levels (None/Error/Warning/Info/Debug/All)

Requirements

  • Go 1.23+

Installation

go get github.com/stremovskyy/go-monobank@latest

Supported API Flows

SDK method Endpoint Purpose
Verification POST /api/merchant/invoice/create Create invoice + enable saveCardData tokenization
VerificationLink POST /api/merchant/invoice/create Convenience helper that returns parsed pageUrl
Payment POST /api/merchant/wallet/payment Charge by cardToken
Status GET /api/merchant/invoice/status Fetch current invoice state
FiscalChecks GET /api/merchant/invoice/fiscal-checks Fetch PRRO fiscal checks for invoice
PublicKey GET /api/merchant/pubkey Fetch webhook verification key
ParseWebhook N/A Parse webhook JSON body
VerifyWebhook N/A Verify X-Sign against raw body
ParseAndVerifyWebhook N/A Verify signature + parse payload

Quick Start

package main

import (
	"fmt"
	"log"
	"os"

	go_monobank "github.com/stremovskyy/go-monobank"
	sdklog "github.com/stremovskyy/go-monobank/log"
)

func main() {
	token := os.Getenv("MONO_TOKEN")
	if token == "" {
		log.Fatal("set MONO_TOKEN")
	}

	client := go_monobank.NewClient(
		go_monobank.WithToken(token),
	)
	client.SetLogLevel(sdklog.LevelInfo)

	resp, err := client.Verification(
		go_monobank.NewRequest().
			WithAmount(100). // 1.00 UAH in minor units
			WithCurrency(go_monobank.CurrencyUAH).
			WithRedirectURL("https://example.com/return").
			WithWebhookURL("https://example.com/webhook").
			WithReference("verify-card-001").
			WithDestination("Card verification").
			SaveCard("customer-wallet-123"),
	)
	if err != nil {
		log.Fatal(err)
	}

	payURL, err := resp.ParsedPageURL()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("invoiceId:", resp.InvoiceID)
	fmt.Println("pageUrl:", payURL.String())
}

VerificationLink(request) internally calls Verification(request).

That means if you call both methods one after another, you create two separate invoices and perform two API requests.

Best practice:

  • Use Verification(...) when you need invoiceId and pageUrl.
  • Use VerificationLink(...) only when you need parsed *url.URL and do not need the original response object.

Convenience helper:

  • If you already called Verification(...), use resp.ParsedPageURL() to parse/validate pageUrl without a second API request.

Payment by Card Token

resp, err := client.Payment(
	go_monobank.NewRequest().
		WithToken(token). // optional if WithToken(...) is set on client
		WithCardToken(cardToken).
		WithAmount(4200).
		WithCurrency(go_monobank.CurrencyUAH).
		WithInitiationKind(go_monobank.InitiationMerchant).
		WithReference("wallet-pay-001").
		WithDestination("Token payment"),
)
if err != nil {
	return err
}

if pe := resp.PaymentError(); pe != nil {
	// business/payment failure (not transport failure)
	fmt.Println(pe.Error())
}

Status and Business Error Inspection

status, err := client.Status(
	go_monobank.NewRequest().
		WithInvoiceID(invoiceID),
)
if err != nil {
	return err
}

if pe := status.PaymentError(); pe != nil {
	fmt.Println("payment failed:", pe)
	for _, m := range pe.Metas {
		fmt.Printf("code=%s text=%s contact=%s\n", m.Code, m.Text, m.Contact)
	}
}

if status.IsFinal() && status.IsSuccess() {
	fmt.Println("payment completed")
}

Fiscal Checks (PRRO)

API docs: https://monobank.ua/api-docs/acquiring/extras/prro/get--api--merchant--invoice--fiscal-checks

fiscal, err := client.FiscalChecks(
	go_monobank.NewRequest().
		WithInvoiceID(invoiceID),
)
if err != nil {
	return err
}

if last, ok := fiscal.LastCheck(); ok {
	fmt.Println("last check id:", last.ID)
	fmt.Println("last check status:", last.Status)
	fmt.Println("is done:", last.IsDone())

	if taxURL, err := last.ParsedTaxURL(); err == nil && taxURL != nil {
		fmt.Println("tax URL:", taxURL.String())
	}
}

fmt.Println("done checks:", len(fiscal.DoneChecks()))
fmt.Println("pending checks:", len(fiscal.PendingChecks()))
fmt.Println("failed checks:", len(fiscal.FailedChecks()))

If you get checks: 0, it usually means there are no fiscal checks for this invoice yet (for example, invoice was created without fiscalization or check generation is still pending).

Webhook Verification

func handler(w http.ResponseWriter, r *http.Request) {
	body, err := io.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "bad body", http.StatusBadRequest)
		return
	}

	xSign := r.Header.Get("X-Sign")
	event, err := client.ParseAndVerifyWebhook(body, xSign)
	if err != nil {
		http.Error(w, "invalid signature", http.StatusUnauthorized)
		return
	}

	_ = event // process event safely
	w.WriteHeader(http.StatusOK)
}

Webhook key resolution order:

  1. WithWebhookPublicKeyPEM(...)
  2. WithWebhookPublicKeyBase64(...)
  3. fetch from /api/merchant/pubkey using default token

Configuration Options

  • WithToken(token) sets default X-Token.
  • WithBaseURL(url) overrides base URL.
  • WithTimeout(d) sets request timeout.
  • WithKeepAlive(d) sets transport keepalive.
  • WithMaxIdleConns(n) sets HTTP max idle connections.
  • WithIdleConnTimeout(d) sets idle connection timeout.
  • WithClient(*http.Client) injects custom HTTP client.
  • WithWebhookPublicKeyBase64(key) sets webhook key (base64 PEM).
  • WithWebhookPublicKeyPEM(pemBytes) sets webhook key (raw PEM).

Request convenience:

  • WithWebhookURL(...) (alias to WithWebHookURL(...))
  • WithWalletID(...)
  • EnableSaveCard() / DisableSaveCard()

Logging

Set SDK log level via:

client.SetLogLevel(sdklog.LevelInfo)

Available levels:

  • LevelNone
  • LevelError
  • LevelWarning
  • LevelInfo
  • LevelDebug
  • LevelAll

Backward-compatible aliases are also available: Off, Error, Warn, Info, Debug.

Dry Run

Dry run skips the outgoing HTTP request and lets you inspect endpoint/payload.

_, _ = client.Verification(
	go_monobank.NewRequest().
		WithAmount(100).
		WithCurrency(go_monobank.CurrencyUAH).
		SaveCard("wallet-id"),
	go_monobank.DryRun(func(endpoint string, payload any) {
		fmt.Println("endpoint:", endpoint)
		fmt.Printf("payload: %#v\n", payload)
	}),
)

If you call DryRun() without a handler, payload is printed through the SDK logger at Info level.

Error Handling

Use standard errors.Is(...) / errors.As(...) patterns.

if err != nil {
	switch {
	case errors.Is(err, go_monobank.ErrValidation):
		// local request validation issue
	case errors.Is(err, go_monobank.ErrTransport):
		// network/TLS/timeout issue
	case errors.Is(err, go_monobank.ErrRateLimited):
		var apiErr *go_monobank.APIError
		if errors.As(err, &apiErr) && apiErr.RetryAfter != nil {
			fmt.Println("retry after:", apiErr.RetryAfter)
		}
	default:
		// fallback
	}
}

Common sentinel errors:

  • ErrValidation
  • ErrEncode
  • ErrTransport
  • ErrDecode
  • ErrBadRequest
  • ErrInvalidToken
  • ErrNotFound
  • ErrMethodNotAllowed
  • ErrRateLimited
  • ErrServerError
  • ErrUnexpectedResponse
  • ErrInvalidSignature
  • ErrPaymentError
Payment Error Explanations (English)

Source docs: https://monobank.ua/api-docs/acquiring/dev/errors/payment

The SDK contains English explanations and contact guidance for all documented errCode values from monobank payment errors page.

status, err := client.Status(go_monobank.NewRequest().WithInvoiceID(invoiceID))
if err != nil {
	return err
}

if pe := status.PaymentError(); pe != nil {
	fmt.Println(pe.Error())
	fmt.Println("contacts:", pe.Contacts())         // e.g. issuing bank / monobank support
	fmt.Println("explanations:", pe.Explanations()) // English explanations from docs
	fmt.Println("hints:", pe.HandlingHints())       // operational next steps
}

// strict handling shortcut:
if err := status.RequireNoPaymentError(); err != nil {
	return err
}

Production Best Practices

  • Use client-level WithToken(...) to avoid repetitive token wiring.
  • Do not call Verification(...) and VerificationLink(...) for the same checkout session.
  • Verify webhook signature against raw bytes before business processing.
  • Treat LevelDebug logs as sensitive in production (payloads may include tokenized payment data).
  • Handle 429 with Retry-After backoff.
  • Keep reference values unique in your own system for better reconciliation.

Examples

Run from repository root:

MONO_TOKEN=... go run ./examples/verification
MONO_TOKEN=... CARD_TOKEN=... go run ./examples/payment_by_token
MONO_TOKEN=... INVOICE_ID=... go run ./examples/status
MONO_TOKEN=... INVOICE_ID=... go run ./examples/fiscal_checks
MONO_TOKEN=... go run ./examples/webhook_http

Contributing

Issues and pull requests are welcome.

License

MIT. See LICENSE.

Documentation

Index

Constants

View Source
const (
	// PaymentErrorContactIssuingBank means customer should contact the card issuing bank.
	PaymentErrorContactIssuingBank = "issuing bank"
	// PaymentErrorContactMonobank means merchant should contact monobank support.
	PaymentErrorContactMonobank = "monobank support"
	// PaymentErrorContactCustomer means customer action is required.
	PaymentErrorContactCustomer = "customer"
	// PaymentErrorContactAPI means integrator/merchant API configuration should be checked.
	PaymentErrorContactAPI = "api/integration team"
)

Variables

View Source
var (
	// ErrValidation indicates a client-side validation issue (missing required fields, invalid input).
	ErrValidation = errors.New("monobank: validation error")
	// ErrEncode indicates a client-side encoding issue (failed to marshal JSON, etc).
	ErrEncode = errors.New("monobank: encode error")
	// ErrTransport indicates a network/transport error (timeouts, DNS, TLS, etc).
	ErrTransport = errors.New("monobank: transport error")
	// ErrDecode indicates a client-side decoding issue (failed to unmarshal JSON, empty body, invalid base64, etc).
	ErrDecode = errors.New("monobank: decode error")

	// ErrBadRequest corresponds to HTTP 400 from API.
	ErrBadRequest = errors.New("monobank: bad request")
	// ErrInvalidToken corresponds to HTTP 403 from API (token invalid).
	ErrInvalidToken = errors.New("monobank: invalid token")
	// ErrNotFound corresponds to HTTP 404 from API.
	ErrNotFound = errors.New("monobank: not found")
	// ErrMethodNotAllowed corresponds to HTTP 405 from API.
	ErrMethodNotAllowed = errors.New("monobank: method not allowed")
	// ErrRateLimited corresponds to HTTP 429 from API.
	ErrRateLimited = errors.New("monobank: rate limited")
	// ErrServerError corresponds to HTTP 5xx from API.
	ErrServerError = errors.New("monobank: server error")
	// ErrUnexpectedResponse is returned when API responds in an unexpected way (unknown status code, invalid content).
	ErrUnexpectedResponse = errors.New("monobank: unexpected response")

	// ErrInvalidSignature is returned when webhook signature validation fails (X-Sign).
	ErrInvalidSignature = errors.New("monobank: invalid webhook signature")

	// ErrPaymentError indicates a business/payment failure (errCode/failureReason from webhook/status).
	ErrPaymentError = errors.New("monobank: payment error")
)
View Source
var PaymentErrorCatalog = map[string][]PaymentErrorMeta{
	"6":    {{Code: "6", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"40":   {{Code: "40", Text: "Card is reported as lost. Spending is restricted.", Contact: PaymentErrorContactIssuingBank}},
	"41":   {{Code: "41", Text: "Card is reported as lost. Spending is restricted.", Contact: PaymentErrorContactIssuingBank}},
	"50":   {{Code: "50", Text: "Card spending is restricted.", Contact: PaymentErrorContactIssuingBank}},
	"51":   {{Code: "51", Text: "The card has expired.", Contact: PaymentErrorContactIssuingBank}},
	"52":   {{Code: "52", Text: "Card number is invalid.", Contact: PaymentErrorContactIssuingBank}},
	"54":   {{Code: "54", Text: "A technical failure occurred.", Contact: PaymentErrorContactIssuingBank}},
	"55":   {{Code: "55", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"56":   {{Code: "56", Text: "Card type does not support this payment.", Contact: PaymentErrorContactIssuingBank}},
	"57":   {{Code: "57", Text: "Transaction is not supported.", Contact: PaymentErrorContactIssuingBank}},
	"58":   {{Code: "58", Text: "Card spending for purchases is restricted.", Contact: PaymentErrorContactIssuingBank}, {Code: "58", Text: "Card spending is restricted.", Contact: PaymentErrorContactIssuingBank}},
	"59":   {{Code: "59", Text: "Insufficient funds to complete the purchase.", Contact: PaymentErrorContactIssuingBank}},
	"60":   {{Code: "60", Text: "Card spending transactions count limit exceeded.", Contact: PaymentErrorContactIssuingBank}},
	"61":   {{Code: "61", Text: "Card internet payment limit exceeded.", Contact: PaymentErrorContactIssuingBank}},
	"62":   {{Code: "62", Text: "PIN retry attempts limit is reached or exceeded.", Contact: PaymentErrorContactIssuingBank}},
	"63":   {{Code: "63", Text: "Card internet payment limit exceeded.", Contact: PaymentErrorContactIssuingBank}},
	"67":   {{Code: "67", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"68":   {{Code: "68", Text: "Payment system declined the transaction.", Contact: PaymentErrorContactIssuingBank}},
	"71":   {{Code: "71", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"72":   {{Code: "72", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"73":   {{Code: "73", Text: "Routing error.", Contact: PaymentErrorContactMonobank}},
	"74":   {{Code: "74", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"75":   {{Code: "75", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"80":   {{Code: "80", Text: "Invalid CVV code.", Contact: PaymentErrorContactIssuingBank}},
	"81":   {{Code: "81", Text: "Invalid CVV2 code.", Contact: PaymentErrorContactIssuingBank}},
	"82":   {{Code: "82", Text: "Transaction is not allowed under these conditions.", Contact: PaymentErrorContactIssuingBank}, {Code: "82", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"83":   {{Code: "83", Text: "Card payment attempts limit exceeded.", Contact: PaymentErrorContactIssuingBank}},
	"84":   {{Code: "84", Text: "Invalid 3-D Secure CAVV value.", Contact: PaymentErrorContactMonobank}},
	"98":   {{Code: "98", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"1000": {{Code: "1000", Text: "Internal technical failure.", Contact: PaymentErrorContactMonobank}},
	"1005": {{Code: "1005", Text: "Internal technical failure.", Contact: PaymentErrorContactMonobank}},
	"1010": {{Code: "1010", Text: "Internal technical failure.", Contact: PaymentErrorContactMonobank}},
	"1014": {{Code: "1014", Text: "Full card details are required to process payment.", Contact: PaymentErrorContactCustomer}},
	"1034": {{Code: "1034", Text: "3-D Secure verification failed.", Contact: PaymentErrorContactIssuingBank}},
	"1035": {{Code: "1035", Text: "3-D Secure verification failed.", Contact: PaymentErrorContactIssuingBank}},
	"1036": {{Code: "1036", Text: "Internal technical failure.", Contact: PaymentErrorContactMonobank}},
	"1044": {{Code: "1044", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"1045": {{Code: "1045", Text: "3-D Secure verification failed.", Contact: PaymentErrorContactIssuingBank}},
	"1053": {{Code: "1053", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"1054": {{Code: "1054", Text: "3-D Secure verification failed.", Contact: PaymentErrorContactMonobank}},
	"1056": {{Code: "1056", Text: "Transfer is allowed only to cards issued by Ukrainian banks.", Contact: PaymentErrorContactMonobank}},
	"1064": {{Code: "1064", Text: "Payment is allowed only with Mastercard or Visa cards.", Contact: PaymentErrorContactIssuingBank}},
	"1066": {{Code: "1066", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"1077": {{Code: "1077", Text: "Payment amount is below minimum allowed amount (payment system settings).", Contact: PaymentErrorContactAPI}},
	"1080": {{Code: "1080", Text: "Card expiry date is invalid.", Contact: PaymentErrorContactIssuingBank}},
	"1090": {{Code: "1090", Text: "Customer information not found.", Contact: PaymentErrorContactMonobank}},
	"1115": {{Code: "1115", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"1121": {{Code: "1121", Text: "Merchant configuration error.", Contact: PaymentErrorContactMonobank}},
	"1145": {{Code: "1145", Text: "Minimum transfer amount is not met.", Contact: PaymentErrorContactMonobank}},
	"1165": {{Code: "1165", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"1187": {{Code: "1187", Text: "Receiver name must be provided.", Contact: PaymentErrorContactAPI}},
	"1193": {{Code: "1193", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"1194": {{Code: "1194", Text: "This top-up method works only with cards issued by other banks.", Contact: PaymentErrorContactMonobank}},
	"1200": {{Code: "1200", Text: "CVV code is required.", Contact: PaymentErrorContactIssuingBank}},
	"1405": {{Code: "1405", Text: "Payment system transfer limits reached.", Contact: PaymentErrorContactIssuingBank}},
	"1406": {{Code: "1406", Text: "Card is blocked by risk management.", Contact: PaymentErrorContactIssuingBank}},
	"1407": {{Code: "1407", Text: "Transaction is blocked by risk management.", Contact: PaymentErrorContactMonobank}},
	"1408": {{Code: "1408", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"1411": {{Code: "1411", Text: "This type of operation from UAH cards is temporarily restricted.", Contact: PaymentErrorContactMonobank}},
	"1413": {{Code: "1413", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"1419": {{Code: "1419", Text: "Card expiry date is invalid.", Contact: PaymentErrorContactIssuingBank}},
	"1420": {{Code: "1420", Text: "Internal technical failure.", Contact: PaymentErrorContactMonobank}},
	"1421": {{Code: "1421", Text: "3-D Secure verification failed.", Contact: PaymentErrorContactIssuingBank}},
	"1422": {{Code: "1422", Text: "Error occurred during 3-D Secure step.", Contact: PaymentErrorContactIssuingBank}},
	"1425": {{Code: "1425", Text: "Error occurred during 3-D Secure step.", Contact: PaymentErrorContactIssuingBank}},
	"1428": {{Code: "1428", Text: "Transaction is blocked by the issuing bank.", Contact: PaymentErrorContactIssuingBank}},
	"1429": {{Code: "1429", Text: "3-D Secure verification failed.", Contact: PaymentErrorContactIssuingBank}},
	"1433": {{Code: "1433", Text: "Check receiver first and last name. If data is invalid, bank can reject the transfer.", Contact: PaymentErrorContactMonobank}},
	"1436": {{Code: "1436", Text: "Payment rejected due to policy restrictions.", Contact: PaymentErrorContactMonobank}},
	"1439": {{Code: "1439", Text: "Operation is not allowed under the eRecovery program.", Contact: PaymentErrorContactMonobank}},
	"1458": {{Code: "1458", Text: "Transaction rejected at 3DS step.", Contact: PaymentErrorContactIssuingBank}},
	"8001": {{Code: "8001", Text: "Payment link has expired.", Contact: PaymentErrorContactCustomer}},
	"8002": {{Code: "8002", Text: "Customer cancelled the payment.", Contact: PaymentErrorContactCustomer}},
	"8003": {{Code: "8003", Text: "Technical failure occurred.", Contact: PaymentErrorContactMonobank}},
	"8004": {{Code: "8004", Text: "3-D Secure processing problem.", Contact: PaymentErrorContactIssuingBank}},
	"8005": {{Code: "8005", Text: "Payment acceptance limits exceeded.", Contact: PaymentErrorContactMonobank}},
	"8006": {{Code: "8006", Text: "Payment acceptance limits exceeded.", Contact: PaymentErrorContactMonobank}},
}

PaymentErrorCatalog maps errCode -> one or more possible meta descriptions. Source: https://monobank.ua/api-docs/acquiring/dev/errors/payment

Functions

This section is empty.

Types

type APIError

type APIError struct {
	// Kind classifies the error for errors.Is(...) matching (ErrBadRequest, ErrInvalidToken, ...).
	Kind error

	Method   string
	Endpoint string

	StatusCode  int
	ContentType string

	// ErrCode/Description are best-effort parsed from the response body.
	ErrCode     string
	Description string

	// Body is a truncated response body (best-effort).
	Body []byte

	// RetryAfter is best-effort parsed from Retry-After header when status=429.
	RetryAfter *time.Duration
}

APIError represents a non-2xx response from monobank API.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Is

func (e *APIError) Is(target error) bool

type CancelItem

type CancelItem struct {
	Status       InvoiceStatus `json:"status"`
	Amount       int64         `json:"amount"`
	Currency     CurrencyCode  `json:"ccy"`
	CreatedDate  time.Time     `json:"createdDate"`
	ModifiedDate time.Time     `json:"modifiedDate"`

	ApprovalCode *string `json:"approvalCode,omitempty"`
	RRN          *string `json:"rrn,omitempty"`
	ExtRef       *string `json:"extRef,omitempty"`

	MaskedPan *string `json:"maskedPan,omitempty"`
}

type CurrencyCode

type CurrencyCode int32

CurrencyCode is ISO 4217 numeric code.

const (
	CurrencyUAH CurrencyCode = 980
)

type DecodeError

type DecodeError struct {
	Op    string
	Msg   string
	Body  []byte
	Cause error
}

DecodeError indicates an issue decoding API/webhook response, signature header, etc.

func (*DecodeError) Error

func (e *DecodeError) Error() string

func (*DecodeError) Is

func (e *DecodeError) Is(target error) bool

func (*DecodeError) Unwrap

func (e *DecodeError) Unwrap() error

type DryRunHandler

type DryRunHandler func(endpoint string, payload any)

DryRunHandler receives info about a skipped request.

type EncodeError

type EncodeError struct {
	Op    string
	Msg   string
	Cause error
}

EncodeError indicates a request/response encoding issue (JSON marshal, etc).

func (*EncodeError) Error

func (e *EncodeError) Error() string

func (*EncodeError) Is

func (e *EncodeError) Is(target error) bool

func (*EncodeError) Unwrap

func (e *EncodeError) Unwrap() error

type FiscalCheck added in v0.2.0

type FiscalCheck struct {
	ID                  string `json:"id"`
	Type                string `json:"type"`
	Status              string `json:"status"`
	StatusDescription   string `json:"statusDescription"`
	TaxURL              string `json:"taxUrl"`
	File                string `json:"file"`
	FiscalizationSource string `json:"fiscalizationSource"`
}

FiscalCheck is one item from FiscalChecksResponse.

func (FiscalCheck) DecodedFile added in v0.2.0

func (c FiscalCheck) DecodedFile() ([]byte, error)

DecodedFile decodes base64-encoded fiscal check file payload.

func (FiscalCheck) IsDone added in v0.2.0

func (c FiscalCheck) IsDone() bool

IsDone reports whether check is completed successfully.

func (FiscalCheck) IsFailed added in v0.2.0

func (c FiscalCheck) IsFailed() bool

IsFailed reports whether check has terminal error-like state.

func (FiscalCheck) IsPending added in v0.2.0

func (c FiscalCheck) IsPending() bool

IsPending reports whether check is neither done nor failed.

func (FiscalCheck) ParsedTaxURL added in v0.2.0

func (c FiscalCheck) ParsedTaxURL() (*url.URL, error)

ParsedTaxURL parses taxUrl as an absolute URL.

type FiscalChecksResponse added in v0.2.0

type FiscalChecksResponse struct {
	Checks []FiscalCheck `json:"checks"`
}

FiscalChecksResponse is returned by GET /api/merchant/invoice/fiscal-checks.

func (*FiscalChecksResponse) DoneChecks added in v0.2.0

func (r *FiscalChecksResponse) DoneChecks() []FiscalCheck

DoneChecks returns checks that are marked as successful/finalized.

func (*FiscalChecksResponse) FailedChecks added in v0.2.0

func (r *FiscalChecksResponse) FailedChecks() []FiscalCheck

FailedChecks returns checks with terminal error-like statuses.

func (*FiscalChecksResponse) FirstCheck added in v0.2.0

func (r *FiscalChecksResponse) FirstCheck() (*FiscalCheck, bool)

FirstCheck returns the first fiscal check and true if present.

func (*FiscalChecksResponse) HasChecks added in v0.2.0

func (r *FiscalChecksResponse) HasChecks() bool

HasChecks reports whether response contains at least one fiscal check.

func (*FiscalChecksResponse) LastCheck added in v0.2.0

func (r *FiscalChecksResponse) LastCheck() (*FiscalCheck, bool)

LastCheck returns the last fiscal check and true if present.

func (*FiscalChecksResponse) PendingChecks added in v0.2.0

func (r *FiscalChecksResponse) PendingChecks() []FiscalCheck

PendingChecks returns checks that are neither done nor failed.

type InitiationKind

type InitiationKind string

InitiationKind defines who initiated the wallet/token payment.

merchant - merchant-initiated (recurring, etc) client - client-initiated (customer requested)

const (
	InitiationMerchant InitiationKind = "merchant"
	InitiationClient   InitiationKind = "client"
)

type InvoiceCreateResponse

type InvoiceCreateResponse struct {
	InvoiceID string `json:"invoiceId"`
	PageURL   string `json:"pageUrl"`
}

InvoiceCreateResponse is returned by POST /api/merchant/invoice/create.

func (*InvoiceCreateResponse) ParsedPageURL added in v0.2.0

func (r *InvoiceCreateResponse) ParsedPageURL() (*url.URL, error)

ParsedPageURL parses response pageUrl as an absolute URL.

type InvoiceStatus

type InvoiceStatus string

InvoiceStatus is a payment/invoice state. We keep it as string to avoid over-restricting API evolution.

const (
	InvoiceCreated    InvoiceStatus = "created"
	InvoiceProcessing InvoiceStatus = "processing"
	InvoiceSuccess    InvoiceStatus = "success"
	InvoiceFailure    InvoiceStatus = "failure"
	InvoiceReversed   InvoiceStatus = "reversed"
	InvoiceExpired    InvoiceStatus = "expired"
)

func (InvoiceStatus) IsFailure added in v0.2.0

func (s InvoiceStatus) IsFailure() bool

IsFailure reports whether status indicates terminal non-success outcome.

func (InvoiceStatus) IsFinal added in v0.2.0

func (s InvoiceStatus) IsFinal() bool

IsFinal reports whether status is final (success or non-success terminal).

func (InvoiceStatus) IsPending added in v0.2.0

func (s InvoiceStatus) IsPending() bool

IsPending reports whether status indicates non-final in-progress state.

func (InvoiceStatus) IsSuccess added in v0.2.0

func (s InvoiceStatus) IsSuccess() bool

IsSuccess reports whether status indicates successful payment completion.

type InvoiceStatusResponse

type InvoiceStatusResponse struct {
	InvoiceID     string        `json:"invoiceId"`
	Status        InvoiceStatus `json:"status"`
	FailureReason *string       `json:"failureReason,omitempty"`
	ErrCode       *string       `json:"errCode,omitempty"`

	Amount      int64        `json:"amount"`
	Currency    CurrencyCode `json:"ccy"`
	FinalAmount *int64       `json:"finalAmount,omitempty"`

	CreatedDate  time.Time `json:"createdDate"`
	ModifiedDate time.Time `json:"modifiedDate"`

	Reference   *string `json:"reference,omitempty"`
	Destination *string `json:"destination,omitempty"`

	CancelList  []CancelItem `json:"cancelList,omitempty"`
	PaymentInfo *PaymentInfo `json:"paymentInfo,omitempty"`
	WalletData  *WalletData  `json:"walletData,omitempty"`
	TipsInfo    *TipsInfo    `json:"tipsInfo,omitempty"`
}

InvoiceStatusResponse is returned by GET /api/merchant/invoice/status and is also the webhook payload body.

func (*InvoiceStatusResponse) IsFailure added in v0.2.0

func (r *InvoiceStatusResponse) IsFailure() bool

IsFailure reports whether invoice status is final non-success.

func (*InvoiceStatusResponse) IsFinal added in v0.2.0

func (r *InvoiceStatusResponse) IsFinal() bool

IsFinal reports whether invoice status is final.

func (*InvoiceStatusResponse) IsPending added in v0.2.0

func (r *InvoiceStatusResponse) IsPending() bool

IsPending reports whether invoice status is not final yet.

func (*InvoiceStatusResponse) IsSuccess added in v0.2.0

func (r *InvoiceStatusResponse) IsSuccess() bool

IsSuccess reports whether invoice status is successful.

func (*InvoiceStatusResponse) PaymentError

func (r *InvoiceStatusResponse) PaymentError() *PaymentError

PaymentError returns business-level payment error (if any) extracted from status/webhook payload.

func (*InvoiceStatusResponse) RequireNoPaymentError added in v0.2.0

func (r *InvoiceStatusResponse) RequireNoPaymentError() error

RequireNoPaymentError returns business payment error if status payload indicates failure.

type Merchant

type Merchant struct {
	Token      string
	CMS        *string
	CMSVersion *string
}

type MerchantPaymInfo

type MerchantPaymInfo struct {
	Reference      string   `json:"reference,omitempty"`
	Destination    string   `json:"destination,omitempty"`
	Comment        string   `json:"comment,omitempty"`
	CustomerEmails []string `json:"customerEmails,omitempty"`
}

MerchantPaymInfo mirrors docs "merchantPaymInfo" (minimal subset). You can extend it later without breaking callers.

type Monobank

type Monobank interface {
	// Verification creates an invoice with saveCardData (tokenization).
	// It returns invoiceId + pageUrl.
	Verification(request *Request, opts ...RunOption) (*InvoiceCreateResponse, error)
	// VerificationLink is a helper that returns only pageUrl as parsed *url.URL.
	VerificationLink(request *Request, opts ...RunOption) (*url.URL, error)

	// Payment performs a charge by tokenized card (wallet/payment).
	Payment(request *Request, opts ...RunOption) (*WalletPaymentResponse, error)

	// Status returns current invoice status (invoice/status).
	Status(request *Request, opts ...RunOption) (*InvoiceStatusResponse, error)
	// FiscalChecks returns PRRO fiscal checks for invoice (invoice/fiscal-checks).
	FiscalChecks(request *Request, opts ...RunOption) (*FiscalChecksResponse, error)

	// PublicKey fetches merchant webhook verification public key (pubkey).
	PublicKey(request *Request, opts ...RunOption) (*PublicKeyResponse, error)

	// ParseWebhook parses webhook JSON body.
	ParseWebhook(body []byte) (*InvoiceStatusResponse, error)
	// VerifyWebhook verifies X-Sign signature against raw body.
	VerifyWebhook(body []byte, xSign string) error
	// ParseAndVerifyWebhook is a convenience method.
	ParseAndVerifyWebhook(body []byte, xSign string) (*InvoiceStatusResponse, error)

	// SetLogLevel changes SDK logging level.
	SetLogLevel(level log.Level)
}

Monobank is the main SDK interface.

Minimal supported flows:

  • Verification (invoice/create + saveCardData)
  • Payment by card token (wallet/payment)
  • Status (invoice/status)
  • Fiscal checks (invoice/fiscal-checks)
  • Webhook parsing + signature verification (X-Sign)

func NewClient

func NewClient(opts ...Option) Monobank

NewClient creates Monobank client with custom options.

func NewDefaultClient

func NewDefaultClient() Monobank

NewDefaultClient returns client with defaults.

type Option

type Option func(*clientConfig)

Option configures Monobank client.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL overrides API base URL.

func WithClient

func WithClient(cl *http.Client) Option

WithClient overrides underlying net/http client.

func WithIdleConnTimeout

func WithIdleConnTimeout(d time.Duration) Option

func WithKeepAlive

func WithKeepAlive(d time.Duration) Option

func WithMaxIdleConns

func WithMaxIdleConns(n int) Option

func WithRecorder added in v0.2.1

func WithRecorder(rec recorder.Recorder) Option

WithRecorder attaches request/response recorder.

func WithTimeout

func WithTimeout(d time.Duration) Option

func WithToken

func WithToken(token string) Option

WithToken sets default X-Token. If request.Merchant.Token is empty, client will use this token.

func WithWebhookPublicKeyBase64

func WithWebhookPublicKeyBase64(key string) Option

WithWebhookPublicKeyBase64 sets base64-encoded PEM public key (from /api/merchant/pubkey).

func WithWebhookPublicKeyPEM

func WithWebhookPublicKeyPEM(pemBytes []byte) Option

WithWebhookPublicKeyPEM sets raw PEM public key.

type PaymentData

type PaymentData struct {
	InvoiceID       *string
	Amount          int64
	Currency        CurrencyCode
	PaymentType     PaymentType
	RedirectURL     *string
	WebHookURL      *string
	ValiditySeconds *int64
	InitiationKind  InitiationKind

	MerchantPaymInfo *MerchantPaymInfo
}

type PaymentError

type PaymentError struct {
	InvoiceID     string
	Status        InvoiceStatus
	ErrCode       string
	FailureReason string

	// Metas are best-effort lookup results from PaymentErrorCatalog by ErrCode.
	// Some codes are duplicated in the docs, so we keep a slice.
	Metas []PaymentErrorMeta
}

PaymentError is a business-level error parsed from webhook/status response fields:

  • errCode
  • failureReason

It is NOT an HTTP/transport error; those are represented by APIError/TransportError/etc.

func NewPaymentError

func NewPaymentError(invoiceID string, status InvoiceStatus, errCode string, failureReason string) *PaymentError

NewPaymentError builds a PaymentError from invoice status/webhook fields.

func (*PaymentError) Contacts added in v0.2.0

func (e *PaymentError) Contacts() []string

Contacts returns deduplicated contact targets.

func (*PaymentError) Error

func (e *PaymentError) Error() string

func (*PaymentError) Explanations added in v0.2.0

func (e *PaymentError) Explanations() []string

Explanations returns deduplicated human-readable explanations.

func (*PaymentError) HandlingHints added in v0.2.0

func (e *PaymentError) HandlingHints() []string

HandlingHints returns deduplicated next-step hints for operational handling.

func (*PaymentError) Is

func (e *PaymentError) Is(target error) bool

func (*PaymentError) PrimaryMeta added in v0.2.0

func (e *PaymentError) PrimaryMeta() (*PaymentErrorMeta, bool)

PrimaryMeta returns first matched metadata entry (if any).

type PaymentErrorMeta

type PaymentErrorMeta struct {
	Code    string
	Text    string
	Contact string
}

PaymentErrorMeta is a human-friendly description for a payment errCode. Source: monobank acquiring docs (payment errors). Note: failureReason from API/webhook is still the most precise explanation.

func LookupPaymentErrorMetas

func LookupPaymentErrorMetas(code string) ([]PaymentErrorMeta, bool)

LookupPaymentErrorMetas returns meta info for the given errCode.

func (PaymentErrorMeta) HandlingHint added in v0.2.0

func (m PaymentErrorMeta) HandlingHint() string

HandlingHint returns a practical next step based on contact target.

type PaymentInfo

type PaymentInfo struct {
	MaskedPan     *string `json:"maskedPan,omitempty"`
	ApprovalCode  *string `json:"approvalCode,omitempty"`
	RRN           *string `json:"rrn,omitempty"`
	TranID        *string `json:"tranId,omitempty"`
	Terminal      *string `json:"terminal,omitempty"`
	PaymentSystem *string `json:"paymentSystem,omitempty"`
	PaymentMethod *string `json:"paymentMethod,omitempty"`
	Fee           *int64  `json:"fee,omitempty"`
}

type PaymentMethod

type PaymentMethod struct {
	CardToken *string

	// WalletID is a merchant-defined identifier for a customer wallet.
	// Used for card tokenization (saveCardData.walletId)
	WalletID *string

	// SaveCard enables tokenization for invoice/create.
	SaveCard bool
}

type PaymentType

type PaymentType string

PaymentType defines operation type.

debit - regular debit hold - hold (requires later finalize), hold lifetime ~9 days (per docs)

const (
	PaymentTypeDebit PaymentType = "debit"
	PaymentTypeHold  PaymentType = "hold"
)

type PublicKeyResponse

type PublicKeyResponse struct {
	Key string `json:"key"`
}

PublicKeyResponse is returned by GET /api/merchant/pubkey. The value is a base64-encoded PEM public key (per docs examples).

type Request

type Request struct {
	Merchant      *Merchant
	PaymentData   *PaymentData
	PaymentMethod *PaymentMethod
}

Request is a unified request object for common monobank acquiring flows. It is intentionally similar to go-ipay/go-platon style (Merchant + PaymentData + PaymentMethod) but exposes fluent/chain setters.

This request is used by:

  • Verification / VerificationLink (invoice/create + saveCardData)
  • Status (invoice/status)
  • Payment (wallet/payment)
  • PublicKey (pubkey)

func NewRequest

func NewRequest() *Request

func (*Request) DisableSaveCard added in v0.2.0

func (r *Request) DisableSaveCard() *Request

DisableSaveCard disables saveCardData for invoice/create.

func (*Request) EnableSaveCard added in v0.2.0

func (r *Request) EnableSaveCard() *Request

EnableSaveCard enables saveCardData for invoice/create.

func (*Request) GetAmount

func (r *Request) GetAmount() int64

func (*Request) GetCardToken

func (r *Request) GetCardToken() string

func (*Request) GetCurrency

func (r *Request) GetCurrency() CurrencyCode

func (*Request) GetInitiationKind

func (r *Request) GetInitiationKind() InitiationKind

func (*Request) GetInvoiceID

func (r *Request) GetInvoiceID() string

func (*Request) GetMerchantPaymInfo

func (r *Request) GetMerchantPaymInfo() *MerchantPaymInfo

func (*Request) GetPaymentType

func (r *Request) GetPaymentType() PaymentType

func (*Request) GetRedirectURL

func (r *Request) GetRedirectURL() *string

func (*Request) GetToken

func (r *Request) GetToken() string

GetToken resolves X-Token from request.

func (*Request) GetValiditySeconds

func (r *Request) GetValiditySeconds() *int64

func (*Request) GetWalletID

func (r *Request) GetWalletID() string

func (*Request) GetWebHookURL

func (r *Request) GetWebHookURL() *string

func (*Request) SaveCard

func (r *Request) SaveCard(walletID string) *Request

SaveCard enables tokenization and sets walletId.

func (*Request) ShouldSaveCard

func (r *Request) ShouldSaveCard() bool

func (*Request) WithAmount

func (r *Request) WithAmount(amountMinor int64) *Request

func (*Request) WithCMS

func (r *Request) WithCMS(name string) *Request

func (*Request) WithCMSVersion

func (r *Request) WithCMSVersion(v string) *Request

func (*Request) WithCardToken

func (r *Request) WithCardToken(cardToken string) *Request

func (*Request) WithComment added in v0.2.2

func (r *Request) WithComment(comment string) *Request

func (*Request) WithCurrency

func (r *Request) WithCurrency(ccy CurrencyCode) *Request

func (*Request) WithDestination

func (r *Request) WithDestination(dest string) *Request

func (*Request) WithInitiationKind

func (r *Request) WithInitiationKind(kind InitiationKind) *Request

func (*Request) WithInvoiceID

func (r *Request) WithInvoiceID(invoiceID string) *Request

func (*Request) WithMerchantPaymInfo

func (r *Request) WithMerchantPaymInfo(info *MerchantPaymInfo) *Request

func (*Request) WithPaymentType

func (r *Request) WithPaymentType(t PaymentType) *Request

func (*Request) WithRedirectURL

func (r *Request) WithRedirectURL(url string) *Request

func (*Request) WithReference

func (r *Request) WithReference(ref string) *Request

func (*Request) WithToken

func (r *Request) WithToken(token string) *Request

WithToken sets X-Token for API calls.

func (*Request) WithValiditySeconds

func (r *Request) WithValiditySeconds(seconds int64) *Request

func (*Request) WithWalletID added in v0.2.0

func (r *Request) WithWalletID(walletID string) *Request

WithWalletID sets wallet identifier without changing SaveCard flag.

func (*Request) WithWebHookURL

func (r *Request) WithWebHookURL(url string) *Request

func (*Request) WithWebhookURL added in v0.2.0

func (r *Request) WithWebhookURL(url string) *Request

WithWebhookURL is an alias for WithWebHookURL.

type RunOption

type RunOption func(*runOptions)

RunOption controls behavior of a single API call.

func DryRun

func DryRun(handler ...DryRunHandler) RunOption

DryRun skips the underlying HTTP call.

Optional handler can be provided to inspect payload.

type SaveCardData

type SaveCardData struct {
	SaveCard bool   `json:"saveCard"`
	WalletID string `json:"walletId,omitempty"`
}

type TipsInfo

type TipsInfo struct {
	EmployeeID *string `json:"employeeId,omitempty"`
	Amount     *int64  `json:"amount,omitempty"`
}

type TransportError

type TransportError struct {
	Op     string
	Method string
	URL    string
	Cause  error
}

TransportError indicates a networking error while calling the API.

func (*TransportError) Error

func (e *TransportError) Error() string

func (*TransportError) Is

func (e *TransportError) Is(target error) bool

func (*TransportError) Unwrap

func (e *TransportError) Unwrap() error

type UnexpectedResponseError

type UnexpectedResponseError struct {
	Op         string
	Method     string
	Endpoint   string
	StatusCode int
	Msg        string
	Body       []byte
}

UnexpectedResponseError indicates an API response that doesn't match expectations (e.g., empty body).

func (*UnexpectedResponseError) Error

func (e *UnexpectedResponseError) Error() string

func (*UnexpectedResponseError) Is

func (e *UnexpectedResponseError) Is(target error) bool

type ValidationError

type ValidationError struct {
	Op    string
	Msg   string
	Cause error
}

ValidationError indicates that a request is missing required fields or has invalid values.

func (*ValidationError) Error

func (e *ValidationError) Error() string

func (*ValidationError) Is

func (e *ValidationError) Is(target error) bool

func (*ValidationError) Unwrap

func (e *ValidationError) Unwrap() error

type WalletData

type WalletData struct {
	CardToken string `json:"cardToken"`
	WalletID  string `json:"walletId"`
	Status    string `json:"status"`
}

type WalletPaymentResponse

type WalletPaymentResponse struct {
	InvoiceID     string        `json:"invoiceId"`
	TDSURL        *string       `json:"tdsUrl,omitempty"`
	Status        InvoiceStatus `json:"status"`
	FailureReason *string       `json:"failureReason,omitempty"`
	Amount        int64         `json:"amount"`
	Currency      CurrencyCode  `json:"ccy"`
	CreatedDate   time.Time     `json:"createdDate"`
	ModifiedDate  time.Time     `json:"modifiedDate"`
}

WalletPaymentResponse is returned by POST /api/merchant/wallet/payment. Also resembles some other payment-related responses.

func (*WalletPaymentResponse) IsFailure added in v0.2.0

func (r *WalletPaymentResponse) IsFailure() bool

IsFailure reports whether wallet payment status is final non-success.

func (*WalletPaymentResponse) IsFinal added in v0.2.0

func (r *WalletPaymentResponse) IsFinal() bool

IsFinal reports whether wallet payment status is final.

func (*WalletPaymentResponse) IsPending added in v0.2.0

func (r *WalletPaymentResponse) IsPending() bool

IsPending reports whether wallet payment status is not final yet.

func (*WalletPaymentResponse) IsSuccess added in v0.2.0

func (r *WalletPaymentResponse) IsSuccess() bool

IsSuccess reports whether wallet payment status is successful.

func (*WalletPaymentResponse) PaymentError

func (r *WalletPaymentResponse) PaymentError() *PaymentError

PaymentError returns business-level payment error (if any) extracted from wallet/payment response. Note: wallet/payment response usually contains failureReason but not errCode. For detailed errCode, call Status(...) or rely on webhook payload.

func (*WalletPaymentResponse) RequireNoPaymentError added in v0.2.0

func (r *WalletPaymentResponse) RequireNoPaymentError() error

RequireNoPaymentError returns business payment error if wallet payment indicates failure.

func (*WalletPaymentResponse) Requires3DS added in v0.2.0

func (r *WalletPaymentResponse) Requires3DS() bool

Requires3DS reports whether response contains non-empty tdsUrl.

type WebhookSignatureError

type WebhookSignatureError struct {
	Op    string
	Msg   string
	Cause error
}

WebhookSignatureError indicates that webhook signature verification failed.

func (*WebhookSignatureError) Error

func (e *WebhookSignatureError) Error() string

func (*WebhookSignatureError) Is

func (e *WebhookSignatureError) Is(target error) bool

func (*WebhookSignatureError) Unwrap

func (e *WebhookSignatureError) Unwrap() error

Directories

Path Synopsis
examples
fiscal_checks command
status command
verification command
webhook_http command
internal

Jump to

Keyboard shortcuts

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