qiwi

package module
v0.0.0-...-95fc8d6 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2023 License: BSD-3-Clause Imports: 15 Imported by: 0

README

QIWI API Go client library

GitHub Actions GoDoc codecov Go Report Card Sourcegraph sendtips FOSSA Status

A Go client library to work with QIWI API.

Install

Install by import github.com/sendtips/qiwi or via go get github.com/sendtips/qiwi

The library support go1.14 and newer.

Library status

Library in early development, we not recommend use it on production till it reach v1.

Tests

Run tests using go test

Example

To obtain a payment session on QIWI website you need to create a new qiwi object via qiwi.New() and call its CardRequest() method.

package main

import (
    "log"
    "context"
    
    "github.com/sendtips/qiwi"
)

func main() {
    pay := qiwi.New("OrderID", "SiteID", "TOKEN", "http://example.com/qiwi-api")

    err := pay.CardRequest(context.TODO(), 300) // Request session for 3.00RUB
    if err != nil {
        log.Fatalf("Error occurred: %s", err)
    }

    log.Printf("Pay via link: %s", pay.PayURL) // Payment session URL on QIWI website
}

License

FOSSA Status

Documentation

Overview

Package qiwi implements QIWI API as a client library.

Behind this library there are two main structures: Payment which carries all our requests and RSP responses and Notify which holds inbound requests from RSP.

For payment sessions are CardRequest, ApplePay and GooglePay methods of Payments are available.

Example to process ApplePay payment

pay := qiwi.New("OrderID", "SiteID", "TOKEN", "http://example.com/qiwi-api")

err := pay.ApplePay(context.TODO(), 300, "ApplePayTokenString") // Request a session for 3.00RUB
if err != nil {
    fmt.Printf("Error occurred: %s", err)
}

You may pass hook payload to NewNotify function, or use NotifyParseHTTPRequest which works directly for http.Request the Notify object will be returned with the payment status.

Example of receiving Notify from incoming http.Request

//..
notify, err := qiwi.NotifyParseHTTPRequest("YOUTOKEN", w.ResponseWriter, r.Request)
if err != nil {
    fmt.Println("[QIWI] Error while loading incoming notification:", err)
}

Or you may process received data by yourself and pass the payload to NewNotify

//..
notify, err := qiwi.NewNotify("YOUTOKEN", "SIGNATURE", payload)
if err != nil {
    fmt.Println("[QIWI] Error while parsing notification:", err)
}

QIWI uses ISO8601 (2021-07-29T16:30:00+03:00) time format, so use a build-in Time custom time type

Index

Constants

View Source
const (
	// Version string.
	Version string = "0.3"
)

Variables

View Source
var (
	// ErrBadJSON error throws when JSON marshal/unmarshal problem occurs.
	ErrBadJSON = errors.New("bad reply payload")
	// ErrBadStatusReply is bad gateway status code.
	ErrBadStatusReply = errors.New("bad status reply")
	// ErrReplyWithError business-logic error.
	ErrReplyWithError = errors.New("error in reply")
	// ErrBadSignature wrong signature error.
	ErrBadSignature = errors.New("wrong signature")
)

Functions

func AddCallbackURLToBill

func AddCallbackURLToBill(p *Payment, url string)

AddCallbackURLToBill adds custom callback URL to Bill. Note, bills used in card payments.

func AddCallbackURLToPayment

func AddCallbackURLToPayment(p *Payment, url string)

AddCallbackURLToPayment adds custom callback URL to Payment.

func PublicLink(pubKey, comment string, amount int) string

PublicLink an easy way to integrate with the QIWI payment form. When the form is opened, the customer is automatically billed for the order. Parameters of the invoice are sent unprotected in the link. A payment form with a choice of payment methods is shown to the customer.

Types

type APHeader

type APHeader struct {
	AppData       string `json:"applicationData,omitempty"`    // optional, HEX-string
	Key           string `json:"wrappedKey,omitempty"`         // used only for RSA_v1
	PubKey        string `json:"ephemeralPublicKey,omitempty"` // used only for EC_v1
	PubKeyHash    string `json:"publicKeyHash"`
	TransactionID string `json:"transactionId"`
}

APHeader holds Header of PKPaymentToken.

type Amount

type Amount struct {
	Value    money    `json:"value"`
	Currency currency `json:"currency"`
}

Amount carry money amount and currency ISO 3-ALPHA code.

func NewAmountInDollars

func NewAmountInDollars(a int) Amount

NewAmountInDollars set amount in US Dollars.

func NewAmountInEuros

func NewAmountInEuros(a int) Amount

NewAmountInEuros set amount to amount in Euros.

func NewAmountInRubles

func NewAmountInRubles(a int) Amount

NewAmountInRubles set amount in Russian Rubles.

type Card

type Card struct {
	CheckDate  Time       `json:"checkOperationDate"`      // System date of the operation
	RequestID  string     `json:"requestUid"`              // Card verification operation unique identifier String(200)
	Status     Status     `json:"status"`                  // Card verification status	String
	Valid      bool       `json:"isValidCard"`             // Logical flag means card is valid for purchases Bool
	T3DS       T3DSStatus `json:"threeDsStatus"`           // Information on customer authentication status.
	CardMethod CardMethod `json:"paymentMethod,omitempty"` // Payment method data for card
	CardInfo   CardInfo   `json:"cardInfo,omitempty"`      // Card information
	CardToken  CardToken  `json:"createdToken,omitempty"`  // Payment token data
}

Card holds data for card payment.

type CardInfo

type CardInfo struct {
	Country       string `json:"issuingCountry"`       // Issuer country code	String(3)
	Bank          string `json:"issuingBank"`          // Issuer name	String
	PaymentSystem string `json:"paymentSystem"`        // Card's payment system	String
	CardType      string `json:"fundingSource"`        // Card's type (debit/credit/..)	String
	Product       string `json:"paymentSystemProduct"` // Card's category	String
}

CardInfo additional information about card.

type CardMethod

type CardMethod struct {
	Type       PaymentType `json:"type"`           // Payment method type
	Payment    string      `json:"maskedPan"`      // Masked card PAN
	Expiration string      `json:"cardExpireDate"` // Card expiration date (MM/YY)
	Name       string      `json:"cardHolder"`     // Cardholder name
}

CardMethod carry card data.

type CardToken

type CardToken struct {
	Token          string `json:"token"`       // Card payment token	String
	Name           string `json:"name"`        // Masked card PAN for which payment token issued	String
	ExpirationDate Time   `json:"expiredDate"` // Payment token expiration date. ISO-8601
	Account        string `json:"account"`     // Customer account for which payment token issued	String
}

CardToken shadowed card.

type CustomField

type CustomField struct {
	CallbackURL string `json:"invoice_callback_url,omitempty"`
}

CustomField in this API used only to set callback url.

type Customer

type Customer struct {
	Account string `json:"account,omitempty"`
	Email   string `json:"email,omitempty"`
	Phone   string `json:"phone,omitempty"`
}

Customer user related data.

type Error

type Error struct {
	Service     string `json:"serviceName,omitempty"` // Service name produced the error
	ErrCode     string `json:"errorCode,omitempty"`   // Error code
	Description string `json:"description,omitempty"` // Error description for RSP
	ErrMessage  string `json:"userMessage,omitempty"` // Error description for Customer
	ErrDate     *Time  `json:"dateTime,omitempty"`    // Error date and time
	TraceID     string `json:"traceId,omitempty"`     // Error Log unique ID
}

Error holds error reply from a carrier.

type Notify

type Notify struct {
	Type      NotifyType `json:"type"` // Notification type
	Payment   Payment    `json:"payment,omitempty"`
	Capture   Payment    `json:"capture,omitempty"`
	Refund    Payment    `json:"refund,omitempty"`
	CheckCard Card       `json:"checkPaymentMethod,omitempty"`
	Version   string     `json:"version"` // Notification version
}

Notify holds incoming data from RSP.

func NewNotify

func NewNotify(signkey, sign string, payload []byte) (*Notify, error)

NewNotify returns Notify data from bytes.

func NotifyParseHTTPRequest

func NotifyParseHTTPRequest(signkey string, w http.ResponseWriter, r *http.Request) (*Notify, error)

NotifyParseHTTPRequest parses http request which returns Notify and also protects against a malicious client streaming an endless request body.

type NotifyType

type NotifyType string

NotifyType from RSP.

const (
	// PaymentNotify for payment notification.
	PaymentNotify NotifyType = "PAYMENT"
	// CaptureNotify for capture (2 stage) payments.
	CaptureNotify NotifyType = "CAPTURE"
	// RefundNotify for refunds.
	RefundNotify NotifyType = "REFUND"
	// CheckCardNotify for card check requests.
	CheckCardNotify NotifyType = "CHECK_CARD"
)

type PKPaymentToken

type PKPaymentToken struct {
	Version   string    `json:"version"`
	Data      string    `json:"data"`
	Header    *APHeader `json:"header"`
	Signature string    `json:"signature"`
}

PKPaymentToken is ApplePay payment token structure see https://developer.apple.com/library/archive/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html

type Payment

type Payment struct {
	PublicKey     string         `json:"-"`                       // Merchant identification key	String	+
	SiteID        string         `json:"siteId,omitempty"`        // RSP site identifier
	BillID        string         `json:"billId,omitempty"`        // Unique invoice identifier in merchant's system. It must be generated on your side with any means. It could be any sequence of digits and letters. Also you might use underscore _ and dash -. If not used, for each URL opening a new invoice is created. String(200)	-
	PaymentID     string         `json:"paymentId,omitempty"`     // Payment operation unique identifier in RSP's system
	CamptureID    string         `json:"captureId,omitempty"`     // Capture operation unique identifier in RSP's system
	RefundID      string         `json:"refundId,omitempty"`      // Refund operation unique identifier in RSP's system
	Amount        Amount         `json:"amount,omitempty"`        // Amount of customer order rounded down to 2 digits (always in rubles)
	PaymentMethod *PaymentMethod `json:"paymentMethod,omitempty"` // Payment method
	Customer      *Customer      `json:"customer,omitempty"`      // Information about the customer
	Creation      *Time          `json:"creationDateTime,omitempty"`
	NotifyDate    *Time          `json:"createddatetime,omitempty"` // Time used in Notify
	Expiration    *Time          `json:"expirationDateTime,omitempty"`
	Comment       string         `json:"comment,omitempty"`     // Comment to the invoice
	CallbackURL   string         `json:"callbackUrl,omitempty"` // Callback URL used to receive notification
	SuccessURL    string         `json:"successUrl,omitempty"`  // URL for redirect from the QIWI form in case of successful payment. URL should be within the merchant's site.
	PayURL        string         `json:"payUrl,omitempty"`      // Payment page on QIWI site
	Req           *Requirements  `json:"requirements,omitempty"`
	CustomField   *CustomField   `json:"customFields,omitempty"`
	Flags         []string       `json:"flags,omitempty"`
	Status        *Status        `json:"status,omitempty"`
	Splits        []*Split       `json:"splits,omitempty"` // https://developer.qiwi.com/en/payments/#payments_split

	Error
	// contains filtered or unexported fields
}

Payment main data structure, holds requests and responses on that requests from RSP.

func New

func New(billID, siteID, token, endpoint string) *Payment

New create card payment session.

func (*Payment) ApplePay

func (p *Payment) ApplePay(ctx context.Context, amount int, token string) (err error)

ApplePay executes payment via ApplePay pass context, amount and ApplePay token string.

func (*Payment) CardRequest

func (p *Payment) CardRequest(ctx context.Context, amount int) error

CardRequest request payment session on RSP site.

func (*Payment) GooglePay

func (p *Payment) GooglePay(ctx context.Context, amount int, token string) error

GooglePay method executes Google Pay payment.

func (*Payment) SBP

func (p *Payment) SBP(ctx context.Context, amount int, comment string) error

SBP returns SBP payment session data. Comment appears in bank payment.

func (*Payment) Split

func (p *Payment) Split(a Amount, merchid string) *Payment

AddSplit without optional fields, see SplitExtra.

func (*Payment) SplitExtra

func (p *Payment) SplitExtra(a Amount, merchid, orderid, c string) *Payment

SplitExtra extends to optional fields.

type PaymentMethod

type PaymentMethod struct {
	Type PaymentType `json:"type,omitempty"` // Payment method type

	PAN string `json:"pan,omitempty"` // optional string(19) Card string //Card number. For type=CARD only

	ExpiryDate string `json:"expiryDate,omitempty"`

	CVV string `json:"cvv2,omitempty"`

	Name string `json:"holderName,omitempty"`

	ApplePayToken *PKPaymentToken `json:"paymentData,omitempty"`
	// optional
	// string
	// Payment token string. For type=TOKEN, APPLE_PAY_TOKEN, GOOGLE_PAY_TOKEN only
	Token string `json:"paymentToken,omitempty"`

	T3DS *T3DS `json:"external3dSec,omitempty"`
}

PaymentMethod holds payment type, card or applepay. googlepay data.

type PaymentType

type PaymentType string

PaymentType holds type of payment.

const (
	// CardPayment for card payments.
	CardPayment PaymentType = "CARD"
	// TokenPayment for shadowed card numbers payment.
	TokenPayment PaymentType = "TOKEN"
	// ApplePayPayment ApplePay payment.
	ApplePayPayment PaymentType = "APPLE_PAY_TOKEN"
	// GooglePayPayment GooglePay payment.
	GooglePayPayment PaymentType = "GOOGLE_PAY_TOKEN"
	// SBPPayment pay via SBP.
	SBPPayment PaymentType = "SBP"
)

type Requirements

type Requirements struct {
	SBP *SBPData `json:"sbp,omitempty"`
}

type SBPData

type SBPData struct {
	QRCodeID string   `json:"qrcId,omitempty"`
	Image    SBPImage `json:"image,omitempty"`
	PayURL   string   `json:"payload,omitempty"`
}

SBP contains Image and URL for SBP payment.

type SBPImage

type SBPImage struct {
	MimeType string `json:"mediaType,omitempty"`
	Picture  string `json:"content,omitempty"`
}

SBPImage holds base64 encoded image of SBP QRCode and its mimetype.

type Signature

type Signature struct {
	Key, Message []byte
	Hash         string
	Valid        bool
}

Signature type holds keys to calculate signature.

func NewSignature

func NewSignature(key, hash string) *Signature

NewSignature return new signature.

func (*Signature) Verify

func (s *Signature) Verify(p *Notify) bool

Verify HMAC-SHA256 signature hash used in Notify type.

type Split

type Split struct {
	Type    SplitDataType `json:"type"`              // String	Data type. Always MERCHANT_DETAILS (merchant details)
	SiteUID string        `json:"siteUid"`           // String	Merchant ID
	Amount  Amount        `json:"splitAmount"`       // Object	Merchant reimbursement data
	OrderID string        `json:"orderId,omitempty"` // String	Order number (optional)
	Comment string        `json:"comment,omitempty"` // string comment	String	Comment for the order (optional)
}

type SplitDataType

type SplitDataType string
const MerchantDetails SplitDataType = "MERCHANT_DETAILS"

type Status

type Status struct {
	Value        StatusCode  `json:"value,omitempty"`
	Date         *Time       `json:"changedDateTime,omitempty"`
	Reason       StatusError `json:"reason,omitempty"`
	ReasonNotify StatusError `json:"reasonCode,omitempty"`
	Message      string      `json:"reasonMessage,omitempty"`
	ErrCode      string      `json:"errorCode,omitempty"`
}

Status of request.

type StatusCode

type StatusCode string

StatusCode operation status reflects its current state.

const (
	StatusCreated   StatusCode = "CREATED"   // For invoices only one status is used
	StatusWait      StatusCode = "WAITING"   // Awaiting for 3DS authentication API responses)
	StatusCompleted StatusCode = "COMPLETED" // Request for authentication is successfully processed API responsess
	StatusOK        StatusCode = "SUCCESS"   // Request for authentication is successfully processed Notifications
	StatusFail      StatusCode = "DECLINE"   // Request for payment confirmation is rejected Notifications, API responses
)

func (*StatusCode) UnmarshalJSON

func (sc *StatusCode) UnmarshalJSON(b []byte) (err error)

type StatusError

type StatusError string

StatusError API errors describe a reason for rejection of the operation.

const (
	StatusInvalidState                StatusError = "INVALID_STATE"                  // Incorrect transaction status
	StatusInvalidAmount               StatusError = "INVALID_AMOUNT"                 // Incorrect payment amount
	StatusDeclinedMPI                 StatusError = "DECLINED_BY_MPI"                // Rejected by MPI
	StatusDeclinedFraud               StatusError = "DECLINED_BY_FRAUD"              // Rejected by fraud monitoring
	StatusGatawayIntegrationError     StatusError = "GATEWAY_INTEGRATION_ERROR"      // Acquirer integration error
	StatusGatawayTechnicalError       StatusError = "GATEWAY_TECHNICAL_ERROR"        // Technical error on acquirer side
	StatusAcquiringMPITechError       StatusError = "ACQUIRING_MPI_TECH_ERROR"       // Technical error on 3DS authentication
	StatusAcquiringGatawayTechError   StatusError = "ACQUIRING_GATEWAY_TECH_ERROR"   // Technical error
	StatusAcquiringAcquirerTechError  StatusError = "ACQUIRING_ACQUIRER_ERROR"       // Technical error
	StatusAcquiringAuthTechnicalError StatusError = "ACQUIRING_AUTH_TECHNICAL_ERROR" // Error on funds authentication
	StatusAcquiringIssuerNotAvailable StatusError = "ACQUIRING_ISSUER_NOT_AVAILABLE" // Issuer error. Issuer is not available at the moment
	StatusAcquiringSuspectedFraud     StatusError = "ACQUIRING_SUSPECTED_FRAUD"      // Issuer error. Fraud suspicion
	StatusAcquiringLimitExceeded      StatusError = "ACQUIRING_LIMIT_EXCEEDED"       // Issuer error. Some limit exceeded
	StatusAcquiringNotPermitted       StatusError = "ACQUIRING_NOT_PERMITTED"        // Issuer error. Operation not allowed
	StatusAcquiringIncorrectCVV       StatusError = "ACQUIRING_INCORRECT_CVV"        // Issuer error. Incorrect CVV
	StatusAcquiringExpiredCard        StatusError = "ACQUIRING_EXPIRED_CARD"         // Issuer error. Incorrect card expiration date
	StatusAcquiringInvalidCard        StatusError = "ACQUIRING_INVALID_CARD"         // Issuer error. Verify card data
	StatusAcquiringInsufficientFunds  StatusError = "ACQUIRING_INSUFFICIENT_FUNDS"   // Issuer error. Not enough funds
	StatusAcquiringUnknown            StatusError = "ACQUIRING_UNKNOWN"              // Unknown error
	StatusBillAlreadyPaid             StatusError = "BILL_ALREADY_PAID"              // Invoice is already paid
	StatusPayinProcessingError        StatusError = "PAYIN_PROCESSING_ERROR"         // Payment processing error
)

type T3DS

type T3DS struct {
	Type string `json:"type"`

	OnlinePaymentCrypto string `json:"onlinePaymentCryptogram,omitempty"`

	Cryptogram string `json:"cryptogram,omitempty"`

	ECIIndicator string `json:"eciIndicator,omitempty"`
}

T3DS 3D-Secure.

type T3DSStatus

type T3DSStatus string

T3DSStatus 3D Secure status.

const (
	Ok3DS   T3DSStatus = "PASSED"     // Ok3DS 3-D Secure passed
	Fail3DS T3DSStatus = "NOT_PASSED" // Fail3DS 3-D Secure not passed)
	None3DS T3DSStatus = "WITHOUT"    // None3DS 3-D Secure not required
)

type Time

type Time struct {
	time.Time
}

Time holds ISO8601 datetime with timezone. Pattern: YYYY-MM-DDThh:mm:ss±hh:mm.

func NowInMoscow

func NowInMoscow() Time

NowInMoscow returns current time in Moscow (MSK+3).

func (Time) Add

func (qt Time) Add(d time.Duration) *Time

Add delta to time.

func (*Time) MarshalJSON

func (qt *Time) MarshalJSON() ([]byte, error)

MarshalJSON packs time.Time to QIWI datetime format.

func (*Time) String

func (qt *Time) String() string

String Stringer interface.

func (*Time) UnmarshalJSON

func (qt *Time) UnmarshalJSON(b []byte) (err error)

UnmarshalJSON unpacks QIWI datetime format in go time.Time.

Jump to

Keyboard shortcuts

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