slip

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 10 Imported by: 0

README

easyslip-go

A small Go client for EasySlip's slip-verification API v2, plus two standalone primitives for matching a verified slip's masked receiver name and account number against an expected value.

Install

go get github.com/Iodize13/easyslip-go

License

MIT

Documentation

Overview

Package slip provides a lightweight Go client for the EasySlip (https://easyslip.com) Thai bank-transfer-slip verification API, plus standalone primitives for matching a verified slip's masked receiver name and account number against an expected value.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidAPIKey  = errors.New("slip: invalid API key")
	ErrSlipNotFound   = errors.New("slip: slip not found")
	ErrQuotaExceeded  = errors.New("slip: quota exceeded")
	ErrAccessDenied   = errors.New("slip: access denied")
	ErrInvalidPayload = errors.New("slip: invalid payload")
	ErrDuplicateSlip  = errors.New("slip: duplicate slip")
	ErrInternal       = errors.New("slip: internal server error")
)

Sentinel errors for documented EasySlip error codes, so callers can distinguish a permanent rejection (e.g. slip not found, bad API key) from a transient/retryable failure (e.g. quota exhaustion, internal error) — see Retryable.

Functions

func Retryable

func Retryable(err error) bool

Retryable reports whether err wraps an EasySlip error code considered transient (quota exhaustion, internal server error) rather than a permanent rejection (not found, invalid API key, invalid payload).

Types

type Account

type Account struct {
	Name  AccountName  `json:"name"`
	Bank  *BankAccount `json:"bank,omitempty"`
	Proxy *Proxy       `json:"proxy,omitempty"`
}

Account is a sender's or receiver's full account block. Bank is present for conventional bank-account receivers; Proxy is present instead for PromptPay/e-wallet receivers — the two are mutually exclusive.

type AccountName

type AccountName struct {
	Th string `json:"th"`
	En string `json:"en"`
}

AccountName is a receiver/sender's account holder name in Thai and English. Thai bank slips truncate the surname to its initial in the En field (e.g. "MR. KRITSADA W") — see MatchName.

type Amount

type Amount struct {
	Amount float64      `json:"amount"`
	Local  *LocalAmount `json:"local,omitempty"`
}

Amount is the transferred amount.

type BankAccount

type BankAccount struct {
	Type    string `json:"type"`
	Account string `json:"account"`
}

BankAccount is a bank account number as reported on the slip. Account is often masked with literal X/x characters in some digit positions, with inconsistent casing and delimiter formatting between calls — see MatchAccountNumber.

type BankRef

type BankRef struct {
	ID    string `json:"id"`
	Name  string `json:"name"`
	Short string `json:"short"`
}

BankRef identifies the bank associated with a sender/receiver.

type Client

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

Client is a thin wrapper around http.Client that adds EasySlip bearer auth.

func New

func New(opts ...Option) *Client

New returns a Client with a 30 s default timeout.

func (*Client) VerifyByImage

func (c *Client) VerifyByImage(ctx context.Context, apiKey, base64Image string) (*VerifyResult, error)

VerifyByImage decodes and verifies a slip from a base64-encoded image. base64Image may include a data-URI prefix (e.g. "data:image/jpeg;base64,...") or be a raw base64 string — EasySlip accepts both.

func (*Client) VerifyByPayload

func (c *Client) VerifyByPayload(ctx context.Context, apiKey, qrPayload string) (*VerifyResult, error)

VerifyByPayload decodes and verifies a slip from its QR-code payload string. This is the cheapest EasySlip call — it requires no image decoding on EasySlip's side — and the only verify method this design's callers use.

func (*Client) VerifyByURL

func (c *Client) VerifyByURL(ctx context.Context, apiKey, imageURL string) (*VerifyResult, error)

VerifyByURL decodes and verifies a slip from a publicly reachable image URL.

type LocalAmount

type LocalAmount struct {
	Amount   float64 `json:"amount"`
	Currency string  `json:"currency"`
}

LocalAmount is the transaction amount converted to a local currency, present for cross-border transfers.

type MatchResult

type MatchResult int

MatchResult is the tri-state outcome of a masked-value comparison. Indeterminate means the input didn't fit the expected masking pattern — callers should route it to a manual fallback rather than treat it as either a match or a mismatch.

const (
	Indeterminate MatchResult = iota
	Match
	NoMatch
)

func MatchAccountNumber

func MatchAccountNumber(expected, maskedValue string) MatchResult

MatchAccountNumber compares expected (an unmasked account number or PromptPay proxy value) against maskedValue, a slip's masked receiver value. Masking uses literal X/x characters (case-inconsistent between calls) and delimiters (dashes, spaces) that are also inconsistent between calls, so both inputs are reduced to their digit/wildcard positions before comparison: expected is stripped to pure digits, maskedValue is stripped to digits and X/x wildcards, and the two are then compared position by position, skipping wildcard positions.

Returns Indeterminate if either input has no digits, if the two reduced values are different lengths (position alignment is undefined), or if maskedValue reveals no digits at all (nothing to compare against).

func MatchName

func MatchName(expected, slipName string) MatchResult

MatchName compares expected (e.g. a registered payment account holder's full name) against slipName, a verified slip's receiver/sender name. Thai banks truncate the surname on the slip to its initial (e.g. "MR. KRITSADA W" for "Kritsada Wattana") — this is the bank's own truncation convention, not a wildcard mask, so MatchName compares the given-name token(s) exactly (case-insensitive) and only the first grapheme cluster of the surname.

Returns Indeterminate if either name has fewer than two tokens after stripping a leading honorific (e.g. a single-word name), since there is no separable given-name/surname to compare.

func (MatchResult) String

func (r MatchResult) String() string

type Option

type Option func(*Client)

Option configures a Client constructed by New.

func WithBaseURL

func WithBaseURL(url string) Option

WithBaseURL overrides the EasySlip API base URL. Used to point the client at a local fake server in tests instead of the real paid API.

type Party

type Party struct {
	Bank    *BankRef `json:"bank,omitempty"`
	Account Account  `json:"account"`
}

Party is one side (sender or receiver) of a verified transfer.

type Proxy

type Proxy struct {
	Type    string `json:"type"`
	Account string `json:"account"`
}

Proxy is a PromptPay/e-wallet receiving target (phone, e-wallet ID, national ID, or tax ID) reported in place of BankAccount when the receiver has no conventional bank account block.

type RawSlip

type RawSlip struct {
	Payload     string  `json:"payload"`
	TransRef    string  `json:"transRef"`
	Date        string  `json:"date"`
	CountryCode string  `json:"countryCode"`
	Amount      Amount  `json:"amount"`
	Fee         float64 `json:"fee"`
	Ref1        string  `json:"ref1,omitempty"`
	Ref2        string  `json:"ref2,omitempty"`
	Ref3        string  `json:"ref3,omitempty"`
	Sender      Party   `json:"sender"`
	Receiver    Party   `json:"receiver"`
}

RawSlip is the decoded "data" object EasySlip returns from POST /verify/bank, unmarshaled exactly as observed in the three captured real response samples. Unknown fields are ignored by default JSON unmarshaling.

type VerifyResult

type VerifyResult = RawSlip

VerifyResult is the public result of a verify call. It is currently identical to RawSlip; kept as a distinct name so the wire-decoding type and the public API surface can diverge later without a breaking rename.

Jump to

Keyboard shortcuts

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