scanpay

package module
v0.0.0-...-c811abc Latest Latest
Warning

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

Go to latest
Published: May 22, 2022 License: MIT Imports: 16 Imported by: 1

README

Scanpay Go client

The official Go client library for the Scanpay API (docs). You can always e-mail us at help@scanpay.dk, or chat with us on IRC at libera.chat #scanpay

Installation

go get github.com/scanpay/go-scanpay

Usage

Create a Scanpay client to start using this library:

var client = scanpay.Client{
    APIKey: " APIKEY ",
}
func (cl *Client) NewURL(req *NewURLReq) error

Use NewURL to create a payment link:

package main
import(
    ".."
    "fmt"
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}

func main() {
    req := scanpay.NewURLReq {
        OrderId: "a766409",
        Language: "da",
        SuccessURL: "https://insertyoursuccesspage.dk",
        Items: []scanpay.Item {
            {
                Name:    "Pink Floyd: The Dark Side Of The Moon",
                Quantity: 2,
                Total:   "199.98 DKK",
                SKU:     "fadf23",
            },
            {
                Name:    "巨人宏偉的帽子",
                Quantity: 2,
                Total:   "840 DKK",
                SKU:     "124",
            },
        },
        Billing: scanpay.Billing{
            Name:    "John Doe",
            Company: "The Shop A/S",
            Email:   "john@doe.com",
            Phone:   "+4512345678",
            Address: []string{"Langgade 23, 2. th"},
            City:    "Havneby",
            Zip:     "1234",
            State:   "",
            Country: "DK",
            VATIN:   "35413308",
            GLN:     "7495563456235",
        },
        Shipping: scanpay.Shipping{
            Name: "Jan Dåh",
            Company: "The Choppa A/S",
            Email: "jan@doh.com",
            Phone: "+4587654321",
            Address: []string{"Langgade 23, 1. th", "C/O The Choppa"},
            City: "Haveby",
            Zip: "1235",
            State: "",
            Country: "DK",
        },
        Options: &scanpay.Options{
            Headers: map[string]string{
                "X-Cardholder-Ip": "111.222.111.222",
            },
        },
    }
    url, err := client.NewURL(&req)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println(url)
}
}
Synchronization

To know when transactions, charges, subscribers and subscriber renewal succeeds, you need to use the synchronization API. It consists of pings which notify you of changes, and the seq request which allows you to pull changes.

func (cl *Client) HandlePing(r *http.Request) error

When changes happen, a ping request will be sent to the ping URL specified in the Scanpay dashboard. Use HandlePing to parse the ping request:

package main
import(
    ".."
    "fmt"
    "net/http"
    "os"
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}

func ping(w http.ResponseWriter, r *http.Request) {
    pingData, err := client.HandlePing(r)
    if err != nil {
        fmt.Println("invalid ping: ", err)
        http.Error(w, "", http.StatusBadRequest)
    } else {
        fmt.Println("Received ping:", pingData)
    }
    os.Exit(0)
}

func main() {
    http.HandleFunc("/ping", ping)
    if err := http.ListenAndServe("localhost:8080", nil); err != nil {
        fmt.Println("http.ListenAndServe failed:", err)
    }
}
func (cl *Client) Seq(req *scanpay.SeqReq) error

To pull changes since last update, use the Seq() call after receiving a ping. Store the returned seq-value in a database and use it for the next Seq() call.

package main
import(
    ".."
    "fmt"
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}
var mySeq = uint64(300)

type Acts []scanpay.Act

func seq(pingSeq uint64) {
    for mySeq < pingSeq {
        seqRes, err := client.Seq(&scanpay.SeqReq{ Seq: mySeq })
        if err != nil {
            fmt.Println("Error:", err)
            return
        }
        for _, change := range seqRes.Changes {
            switch change.Type {
            case "transaction", "charge":
                fmt.Printf("Order %s change\n" +
                           "Transaction id: %d\n" +
                           "Revision: %d\n" +
                           "Acts: %#v\n\n",
                           change.OrderId, change.Id, change.Rev, change.Acts)
            case "subscriber":
                fmt.Printf("Subscriber %s change\n" +
                           "Subscriber id: %d\n" +
                           "Revision: %d\n" +
                           "Acts %#v\n\n",
                           change.Ref, change.Id, change.Rev, change.Acts)
            }
        }
        mySeq = seqRes.Seq
        if len(seqRes.Changes) == 0 {
            break
        }
    }
    fmt.Println("final mySeq =", mySeq)
}

func main() {
    pingSeq := uint64(400)
    seq(pingSeq)
}
Transaction Actions
func (cl *Client) Capture(req *CaptureReq) error

Use Capture to capture a transaction.

package main
import(
    "fmt"
    "github.com/scanpay/go-scanpay"
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}

func main() {
    req := scanpay.CaptureReq{
        TransactionId: uint64(750),
        Total: "123 DKK",
        Index: 0,
    }
    if err := client.Capture(&req); err != nil {
        fmt.Println("Capture failed:", err)
    } else {
        fmt.Println("Capture succeeded")
    }
}
func (cl *Client) Refund(req *RefundReq) error

Use Refund to refund a captured transaction.

package main
import(
    ".."
    "fmt"
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}

func main() {
    req := scanpay.RefundReq{
        TransactionId: uint64(750),
        Total: "123 DKK",
        Index: 1,
    }
    if err := client.Refund(&req); err != nil {
        fmt.Println("Refund failed:", err)
    } else {
        fmt.Println("Refund succeeded")
    }
}
func (cl *Client) Void(req *VoidReq) error

Use Void to void the amount authorized by the transaction.

package main
import(
    "fmt"
    "github.com/scanpay/go-scanpay"
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}

func main() {
    req := scanpay.VoidReq{
        TransactionId: uint64(750),
        Index: 0,
    }
    if err := client.Void(&req); err != nil {
        fmt.Println("Void failed:", err)
    } else {
        fmt.Println("Void succeeded")
    }
}
Subscriptions

Create a subscriber by using NewURL with a Subscriber parameter.

package main
import(
    ".."
    "fmt"
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}

func main() {
    req := scanpay.NewURLReq {
        Subscriber: &scanpay.Subscriber{
            Ref: "99",
        },
        Options: &scanpay.Options{
            Headers: map[string]string{
                "X-Cardholder-Ip": "111.222.111.222",
            },
        },
    }
    url, err := client.NewURL(&req)
    if err != nil {
        fmt.Println("NewURL error:", err)
        return
    }
    fmt.Println(url)
}
func (cl *Client) Charge(req *ChargeReq) error

Use Charge to charge a subscriber. The subscriber id is obtained with seq.

package main
import(
    "fmt"
    ".."
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}

func main() {
    req := scanpay.ChargeReq{
        SubscriberId: 30,
        Items: []scanpay.Item{
            {
                Name:"some item",
                Total: "123 DKK",
            },
        },
    }
    if res, err := client.Charge(&req); err != nil {
        fmt.Println("Charge failed:", err)
    } else {
        fmt.Println("Charge succeeded", res)
    }
}
func (cl *Client) Renew(req *RenewReq) error

Use Renew to renew a subscriber, i.e. to attach a new card, if it has expired.

package main
import(
    ".."
    "fmt"
    "time"
)

var client = scanpay.Client{
    APIKey: "1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W",
    Host: "api.test.scanpay.dk",
}

func main() {
    req := scanpay.RenewReq {
        SubscriberId: 30,
        Language: "da",
        SuccessURL: "https://scanpay.dk",
        Lifetime: 24 * time.Hour,
    }

    if url, err := client.Renew(&req); err != nil {
        fmt.Println("Renew failed:", err)
    } else {
        fmt.Println("Renew URL:", url)
    }
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsIdempotentResponseError

func IsIdempotentResponseError(err error) bool

Check if idempotency-key should be reused

Types

type Act

type Act struct {
	Action string `json:"act"`
	Time   int64  `json:"time"`
	Total  string `json:"total"`
}

Sequence request

type ActReq

type ActReq struct {
	TransactionId uint64   `json:"-"`
	Total         string   `json:"total"`
	Index         uint64   `json:"index"`
	Options       *Options `json:"-"`
}

type Billing

type Billing struct {
	Name    string   `json:"name,omitempty"`
	Company string   `json:"company,omitempty"`
	Email   string   `json:"email,omitempty"`
	Phone   string   `json:"phone,omitempty"`
	Address []string `json:"address,omitempty"`
	City    string   `json:"city,omitempty"`
	Zip     string   `json:"zip,omitempty"`
	State   string   `json:"state,omitempty"`
	Country string   `json:"country,omitempty"`
	VATIN   string   `json:"vatin,omitempty"`
	GLN     string   `json:"gln,omitempty"`
}

type CaptureReq

type CaptureReq ActReq

type Change

type Change struct {
	Type    string `json:"type"`
	Error   string `json:"error"`
	Id      uint64 `json:"id"`
	Rev     uint32 `json:"rev"`
	OrderId string `json:"orderid"`
	Time    struct {
		Created    int64 `json:"created"`
		Authorized int64 `json:"authorized"`
	} `json:"time"`
	Acts   []Act `json:"acts"`
	Totals struct {
		Authorized string `json:"authorized"`
		Captured   string `json:"captured"`
		Refunded   string `json:"refunded"`
		Left       string `json:"left"`
	} `json:"totals"`

	/* type=subscriber specific data */
	Ref string `json:"ref"`

	/* type=charge specific data */
	Subscriber struct {
		Id  uint64 `json:"id"`
		Ref string `json:"ref"`
	} `json:"subscriber"`
}

type ChargeReq

type ChargeReq struct {
	SubscriberId uint64   `json:"-"`
	OrderId      string   `json:"orderid"`
	AutoCapture  bool     `json:"autocapture"`
	Items        []Item   `json:"items"`
	Billing      Billing  `json:"billing"`
	Shipping     Shipping `json:"shipping"`
	Options      *Options `json:"-"`
}

type ChargeRes

type ChargeRes struct {
	Id     uint64 `json:"id"`
	Totals struct {
		Authorized string `json:"authorized"`
	} `json:"totals"`
}

type Client

type Client struct {
	APIKey     string
	Host       string
	Insecure   bool
	HttpClient *http.Client
}

func (*Client) Capture

func (c *Client) Capture(data *CaptureReq) error

func (*Client) Charge

func (c *Client) Charge(data *ChargeReq) (*ChargeRes, error)

func (*Client) HandlePing

func (c *Client) HandlePing(req *http.Request) (*Ping, error)

func (*Client) NewURL

func (c *Client) NewURL(data *NewURLReq) (string, error)

func (*Client) Refund

func (c *Client) Refund(data *RefundReq) error

func (*Client) Renew

func (c *Client) Renew(data *RenewReq) (string, error)

func (*Client) Seq

func (c *Client) Seq(data *SeqReq) (*SeqRes, error)

func (*Client) Void

func (c *Client) Void(data *VoidReq) error

type Item

type Item struct {
	Name     string `json:"name,omitempty"`
	Quantity uint64 `json:"quantity,omitempty"`
	Total    string `json:"total,omitempty"`
	SKU      string `json:"sku,omitempty"`
}

New Payid

type LifetimeDuration

type LifetimeDuration time.Duration

func (*LifetimeDuration) MarshalText

func (d *LifetimeDuration) MarshalText() ([]byte, error)

type NewURLReq

type NewURLReq struct {
	OrderId     string      `json:"orderid,omitempty"`
	Language    string      `json:"language,omitempty"`
	SuccessURL  string      `json:"successurl,omitempty"`
	AutoCapture bool        `json:"autocapture,omitempty"`
	Items       []Item      `json:"items,omitempty"`
	Subscriber  *Subscriber `json:"subscriber,omitempty"`
	Billing     Billing     `json:"billing,omitempty"`
	Shipping    Shipping    `json:"shipping,omitempty"`
	Options     *Options    `json:"-"`
}

type Options

type Options struct {
	Headers map[string]string
}

type Ping

type Ping struct {
	ShopId uint64 `json:"shopid"`
	Seq    uint64 `json:"seq"`
}

type RefundReq

type RefundReq ActReq

type RenewReq

type RenewReq struct {
	SubscriberId uint64        `json:"-"`
	Language     string        `json:"language,omitempty"`
	SuccessURL   string        `json:"successurl,omitempty"`
	Lifetime     time.Duration `json:"lifetime,omitempty"`
	Options      *Options      `json:"-"`
}

type SeqReq

type SeqReq struct {
	Seq     uint64   `json:"seq"`
	Options *Options `json:"-"`
}

type SeqRes

type SeqRes struct {
	Seq     uint64   `json:"seq"`
	Changes []Change `json:"changes"`
}

type Shipping

type Shipping struct {
	Name    string   `json:"name,omitempty"`
	Company string   `json:"company,omitempty"`
	Email   string   `json:"email,omitempty"`
	Phone   string   `json:"phone,omitempty"`
	Address []string `json:"address,omitempty"`
	City    string   `json:"city,omitempty"`
	Zip     string   `json:"zip,omitempty"`
	State   string   `json:"state,omitempty"`
	Country string   `json:"country,omitempty"`
}

type Subscriber

type Subscriber struct {
	Ref string `json:"ref,omitempty"`
}

type VoidReq

type VoidReq ActReq

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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