Help us shape the future of Go! Take the 2026 Go Developer Survey

paymenku

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 15 Imported by: 0

README

paymenku/sdk-go

SDK Go untuk API Paymenku — QRIS, Virtual Account, e-wallet, gerai ritel, payment link, dan wallet. Tanpa dependensi eksternal, Go 1.22+.

Instalasi

go get github.com/paymenku/sdk-go

Mulai cepat

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	paymenku "github.com/paymenku/sdk-go"
)

func main() {
	client, err := paymenku.NewClient(os.Getenv("PAYMENKU_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}

	trx, err := client.Transactions.Create(context.Background(), paymenku.CreateTransactionInput{
		ChannelCode:   "qris",
		Amount:        15000,
		ReferenceID:   "INV-20261027-001",
		CustomerName:  "Budi Santoso",
		CustomerEmail: "budi@example.com",
		ReturnURL:     "https://tokoanda.com/selesai",
	}, paymenku.WithIdempotencyKey("INV-20261027-001"))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(trx.TrxID, trx.PayURL)
}

Kunci sk_test_... membuat transaksi sandbox; sk_live_... memakai dana nyata dan memerlukan KYC yang disetujui.

Transaksi

ctx := context.Background()

// Cek status berdasarkan trx_id atau reference_id
trx, err := client.Transactions.Get(ctx, "INV-20261027-001")

// Daftar transaksi
page, perPage := 2, 5
sandbox := false
hasil, err := client.Transactions.List(ctx, paymenku.ListTransactionsParams{
	Page:      &page,
	PerPage:   &perPage,
	Status:    "paid",
	IsSandbox: &sandbox,
})
// hasil.Data, hasil.Pagination

// Batalkan transaksi pending
_, err = client.Transactions.Cancel(ctx, trx.TrxID)

// Refund transaksi paid
_, err = client.Transactions.Refund(ctx, trx.TrxID, 25950, "Pesanan dibatalkan")

Kanal, fee, dan instruksi

channels, err := client.PaymentChannels.List(ctx)

fees, err := client.Fees.Calculate(ctx, 100000, "qris")

allowHTML := false
nominal := int64(100000)
langkah, err := client.PaymentInstructions.Get(ctx, "bca_va", paymenku.InstructionOptions{
	PayCode:   "1234567890",
	Amount:    &nominal,
	AllowHTML: &allowHTML,
})
link, err := client.PaymentLinks.Create(ctx, paymenku.CreatePaymentLinkInput{
	Amount:        150000,
	Title:         "Invoice #1024",
	CustomerName:  "Budi Santoso",
	CustomerEmail: "budi@example.com",
})

detail, err := client.PaymentLinks.Get(ctx, link.LinkID)

Payment link hanya menerima kunci live (sk_live_).

Wallet

saldo, err := client.Wallet.Balance(ctx)
kliring, err := client.Wallet.PendingBalance(ctx)

Galat

var apiErr *paymenku.APIError
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.StatusCode) // 422
	fmt.Println(apiErr.Message)    // Validation failed
	fmt.Println(apiErr.Errors)     // map[amount:[validation.min]]
	fmt.Println(apiErr.ErrorCode)
}

var netErr *paymenku.NetworkError
if errors.As(err, &netErr) {
	// timeout atau koneksi gagal
}
  • *APIError dilempar untuk HTTP 4xx/5xx dan envelope status: "error" / success: false meskipun HTTP 200.
  • *NetworkError untuk timeout/koneksi gagal.
  • *ResponseError bila respons bukan JSON.

SDK tidak melakukan percobaan ulang otomatis. Untuk 429, hormati Retry-After; untuk 5xx, ulangi dengan backoff dan Idempotency-Key.

Webhook

func handler(w http.ResponseWriter, r *http.Request) {
	raw, _ := io.ReadAll(r.Body)

	valid := paymenku.VerifyWebhook(
		raw,
		r.Header.Get("X-PaymenKu-Timestamp"),
		r.Header.Get("X-PaymenKu-Signature"),
		os.Getenv("PAYMENKU_WEBHOOK_SECRET"),
	)
	if !valid {
		http.Error(w, "invalid signature", http.StatusUnauthorized)
		return
	}

	w.WriteHeader(http.StatusOK)
	// proses setelah response; idempoten per trx_id
}

Jangan parse JSON lalu marshal ulang sebelum verifikasi — urutan kunci dan spasi berubah dan tanda tangan tidak cocok.

Konfigurasi

client, err := paymenku.NewClient(apiKey,
	paymenku.WithBaseURL("https://paymenku.com/api/v1"), // bawaan
	paymenku.WithTimeout(30*time.Second),                // bawaan
	paymenku.WithHTTPClient(customClient),               // opsional
)

Catatan

  • Nominal pada respons berupa string desimal ("15305.00").
  • PaymentInfo berbeda per kanal; TransactionID tidak selalu ada.
  • Status resmi datang dari webhook, bukan polling.
  • Header rate limit belum diekspos; gunakan WithHTTPClient dengan transport kustom bila perlu membaca headers mentah.

Pengembangan

go test ./...
go vet ./...

Lisensi MIT.

Documentation

Index

Constants

View Source
const (
	// DefaultBaseURL adalah base URL API Paymenku.
	DefaultBaseURL = "https://paymenku.com/api/v1"
	// Version adalah versi SDK.
	Version = "0.1.0"
)

Variables

This section is empty.

Functions

func VerifyWebhook

func VerifyWebhook(rawBody []byte, timestamp, signature, secret string) bool

VerifyWebhook memverifikasi header X-PaymenKu-Signature. Rumus: HMAC-SHA256(timestamp + "." + rawBody, secret) dalam hex.

rawBody harus body mentah persis seperti diterima, sebelum di-parse JSON.

Types

type APIError

type APIError struct {
	StatusCode int
	Message    string
	Errors     map[string][]string
	ErrorCode  string
	Body       []byte
}

APIError adalah galat yang dikembalikan API (HTTP 4xx/5xx atau envelope error).

func (*APIError) Error

func (e *APIError) Error() string

type CancelResult

type CancelResult struct {
	TrxID   string `json:"trx_id"`
	Status  string `json:"status"`
	Message string `json:"-"`
}

CancelResult adalah hasil pembatalan transaksi.

type Client

type Client struct {
	Transactions        *TransactionsService
	PaymentChannels     *PaymentChannelsService
	Fees                *FeesService
	PaymentInstructions *PaymentInstructionsService
	PaymentLinks        *PaymentLinksService
	Wallet              *WalletService
	// contains filtered or unexported fields
}

Client adalah klien API Paymenku.

func NewClient

func NewClient(apiKey string, opts ...Option) (*Client, error)

NewClient membuat klien dengan kunci API live atau sandbox.

type CreatePaymentLinkInput

type CreatePaymentLinkInput struct {
	Amount           int64       `json:"amount"`
	Title            string      `json:"title,omitempty"`
	Description      string      `json:"description,omitempty"`
	CustomerName     string      `json:"customer_name"`
	CustomerEmail    string      `json:"customer_email"`
	ReturnURL        string      `json:"return_url,omitempty"`
	ExpiresInMinutes *int        `json:"expires_in_minutes,omitempty"`
	IsSingleUse      *bool       `json:"is_single_use,omitempty"`
	OrderItems       []OrderItem `json:"order_items,omitempty"`
}

CreatePaymentLinkInput adalah body POST /payment-link/create.

type CreateTransactionInput

type CreateTransactionInput struct {
	ChannelCode   string      `json:"channel_code"`
	Amount        int64       `json:"amount"`
	ReferenceID   string      `json:"reference_id"`
	CustomerName  string      `json:"customer_name"`
	CustomerEmail string      `json:"customer_email"`
	CustomerPhone string      `json:"customer_phone,omitempty"`
	ReturnURL     string      `json:"return_url"`
	OrderItems    []OrderItem `json:"order_items,omitempty"`
}

CreateTransactionInput adalah body POST /transaction/create.

type CreatedTransaction

type CreatedTransaction struct {
	TrxID         string      `json:"trx_id"`
	ReferenceID   string      `json:"reference_id"`
	Amount        string      `json:"amount"`
	Status        string      `json:"status"`
	PayURL        string      `json:"pay_url"`
	PaymentInfo   PaymentInfo `json:"payment_info"`
	SandboxMode   *bool       `json:"sandbox_mode"`
	SandboxNotice *string     `json:"sandbox_notice"`
}

CreatedTransaction adalah data pada respons pembuatan transaksi.

type FeeEstimate

type FeeEstimate struct {
	Code  string `json:"code"`
	Name  string `json:"name"`
	Group string `json:"group"`
	Type  string `json:"type"`
	Flow  string `json:"flow"`
	Fee   struct {
		Flat    float64 `json:"flat"`
		Percent float64 `json:"percent"`
	} `json:"fee"`
	TotalFee struct {
		Merchant float64 `json:"merchant"`
		Customer float64 `json:"customer"`
	} `json:"total_fee"`
	FeeMode string `json:"fee_mode"`
	Limits  struct {
		MinAmount        int64  `json:"min_amount"`
		MaxAmount        *int64 `json:"max_amount"`
		MinExpiryMinutes int    `json:"min_expiry_minutes"`
		MaxExpiryMinutes int    `json:"max_expiry_minutes"`
	} `json:"limits"`
}

FeeEstimate adalah satu baris hasil perhitungan fee.

type FeesService

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

FeesService menangani perhitungan fee.

func (*FeesService) Calculate

func (s *FeesService) Calculate(
	ctx context.Context,
	amount int64,
	code string,
	opts ...RequestOption,
) ([]FeeEstimate, error)

Calculate menghitung fee untuk satu nominal; code opsional.

type InstructionOptions

type InstructionOptions struct {
	PayCode   string
	Amount    *int64
	AllowHTML *bool
}

InstructionOptions adalah parameter opsional panduan bayar.

type ListTransactionsParams

type ListTransactionsParams struct {
	Page        *int
	PerPage     *int
	Status      string
	ChannelCode string
	ReferenceID string
	DateFrom    string
	DateTo      string
	IsSandbox   *bool
	SortBy      string
	SortOrder   string
}

ListTransactionsParams berisi filter opsional daftar transaksi.

type NetworkError

type NetworkError struct {
	Err error
}

NetworkError adalah kegagalan koneksi atau timeout.

func (*NetworkError) Error

func (e *NetworkError) Error() string

func (*NetworkError) Unwrap

func (e *NetworkError) Unwrap() error

type Option

type Option func(*Client)

Option mengubah konfigurasi Client.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL mengganti base URL (misalnya untuk pengujian).

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient memakai http.Client milik pemanggil.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout mengatur timeout permintaan bila http.Client belum diberikan.

func WithUserAgent

func WithUserAgent(userAgent string) Option

WithUserAgent mengganti User-Agent.

type OrderItem

type OrderItem struct {
	Name     string `json:"name"`
	Quantity int    `json:"quantity,omitempty"`
}

OrderItem adalah rincian produk pada transaksi atau payment link.

type Pagination

type Pagination struct {
	CurrentPage int  `json:"current_page"`
	PerPage     int  `json:"per_page"`
	Total       int  `json:"total"`
	TotalPages  int  `json:"total_pages"`
	HasMore     bool `json:"has_more"`
}

Pagination adalah metadata halaman pada daftar transaksi.

type PaymentChannel

type PaymentChannel struct {
	Code       string  `json:"code"`
	Name       string  `json:"name"`
	Type       string  `json:"type"`
	Group      *string `json:"group"`
	FlowType   string  `json:"flow_type"`
	Icon       *string `json:"icon"`
	FeeMode    string  `json:"fee_mode"`
	FeeFlat    float64 `json:"fee_flat"`
	FeePercent float64 `json:"fee_percent"`
	MinAmount  *int64  `json:"min_amount"`
	MaxAmount  *int64  `json:"max_amount"`
}

PaymentChannel adalah kanal aktif milik merchant.

type PaymentChannelSummary

type PaymentChannelSummary struct {
	Code string `json:"code"`
	Name string `json:"name"`
	Type string `json:"type"`
}

PaymentChannelSummary adalah ringkasan kanal pada transaksi.

type PaymentChannelsService

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

PaymentChannelsService menangani daftar kanal pembayaran.

func (*PaymentChannelsService) List

List mengembalikan kanal yang aktif untuk merchant.

type PaymentInfo

type PaymentInfo struct {
	TransactionID     *string          `json:"transaction_id"`
	TransactionStatus *string          `json:"transaction_status"`
	VANumber          *string          `json:"va_number"`
	Bank              *string          `json:"bank"`
	PaymentCode       *string          `json:"payment_code"`
	Store             *string          `json:"store"`
	CheckoutURL       *string          `json:"checkout_url"`
	CheckoutURLApp    *string          `json:"checkout_url_app"`
	PaymentActions    []map[string]any `json:"payment_actions"`
	QRURL             *string          `json:"qr_url"`
	QRString          *string          `json:"qr_string"`
	MerchantName      *string          `json:"merchant_name"`
	ExpirationDate    *string          `json:"expiration_date"`
	Sandbox           *bool            `json:"sandbox"`
	SimulatorURL      *string          `json:"simulator_url"`
}

PaymentInfo bentuknya bergantung kanal. Tidak semua field terisi; TransactionID tidak ada pada QRIS Custom.

type PaymentInstruction

type PaymentInstruction struct {
	Title string   `json:"title"`
	Steps []string `json:"steps"`
}

PaymentInstruction adalah panduan bayar untuk satu metode.

type PaymentInstructionsService

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

PaymentInstructionsService menangani panduan cara bayar.

func (*PaymentInstructionsService) Get

Get mengambil langkah pembayaran untuk satu kanal.

type PaymentLink struct {
	LinkID           string      `json:"link_id"`
	PaymentURL       string      `json:"payment_url"`
	Title            string      `json:"title"`
	Description      *string     `json:"description"`
	Amount           float64     `json:"amount"`
	Items            []OrderItem `json:"items"`
	Status           string      `json:"status"`
	IsSingleUse      bool        `json:"is_single_use"`
	ExpiresAt        string      `json:"expires_at"`
	ExpiresInMinutes *int        `json:"expires_in_minutes"`
	CustomerName     string      `json:"customer_name"`
	CustomerEmail    string      `json:"customer_email"`
	ReturnURL        *string     `json:"return_url"`
	CreatedAt        string      `json:"created_at"`
}

PaymentLink adalah tautan checkout.

type PaymentLinkDetail

type PaymentLinkDetail struct {
	PaymentLink
	Tersedia  bool `json:"tersedia"`
	Transaksi *struct {
		TrxID  string  `json:"trx_id"`
		Status string  `json:"status"`
		PaidAt *string `json:"paid_at"`
	} `json:"transaksi"`
}

PaymentLinkDetail menambahkan status ketersediaan dan transaksi terkait.

type PaymentLinksService

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

PaymentLinksService menangani tautan checkout.

func (*PaymentLinksService) Create

Create membuat payment link (hanya kunci live).

func (*PaymentLinksService) Get

func (s *PaymentLinksService) Get(
	ctx context.Context,
	linkID string,
	opts ...RequestOption,
) (*PaymentLinkDetail, error)

Get mengambil detail payment link.

type PendingBalance

type PendingBalance struct {
	PendingBalance string `json:"pending_balance"`
	Currency       string `json:"currency"`
	Formatted      string `json:"formatted"`
	ClearingDays   int    `json:"clearing_days"`
	Note           string `json:"note"`
}

PendingBalance adalah saldo dalam kliring.

type RefundResult

type RefundResult struct {
	TrxID            string  `json:"trx_id"`
	Status           string  `json:"status"`
	RefundAmount     float64 `json:"refund_amount"`
	MerchantRefundNo string  `json:"merchant_refund_no"`
	Message          string  `json:"-"`
}

RefundResult adalah hasil refund transaksi.

type RequestOption

type RequestOption func(*requestConfig)

RequestOption mengubah satu permintaan.

func WithIdempotencyKey

func WithIdempotencyKey(key string) RequestOption

WithIdempotencyKey mengirim header Idempotency-Key.

type ResponseError

type ResponseError struct {
	StatusCode int
	Body       []byte
}

ResponseError adalah respons yang tidak dapat di-parse sebagai JSON.

func (*ResponseError) Error

func (e *ResponseError) Error() string

type Transaction

type Transaction struct {
	TrxID          string                 `json:"trx_id"`
	ReferenceID    string                 `json:"reference_id"`
	Amount         string                 `json:"amount"`
	TotalFee       string                 `json:"total_fee"`
	AmountReceived string                 `json:"amount_received"`
	Status         string                 `json:"status"`
	IsSandbox      bool                   `json:"is_sandbox"`
	CustomerName   string                 `json:"customer_name"`
	CustomerEmail  string                 `json:"customer_email"`
	CustomerPhone  *string                `json:"customer_phone"`
	OrderItems     []OrderItem            `json:"order_items"`
	PaymentChannel *PaymentChannelSummary `json:"payment_channel"`
	PayURL         string                 `json:"pay_url"`
	PaidAt         *string                `json:"paid_at"`
	CreatedAt      string                 `json:"created_at"`
	UpdatedAt      string                 `json:"updated_at"`
}

Transaction adalah transaksi pada respons cek status dan daftar transaksi.

type TransactionList

type TransactionList struct {
	Data       []Transaction
	Pagination Pagination
}

TransactionList adalah hasil GET /transactions.

type TransactionsService

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

TransactionsService menangani endpoint transaksi.

func (*TransactionsService) Cancel

func (s *TransactionsService) Cancel(
	ctx context.Context,
	trxID string,
	opts ...RequestOption,
) (*CancelResult, error)

Cancel membatalkan transaksi yang masih pending.

func (*TransactionsService) Create

Create membuat transaksi baru.

func (*TransactionsService) Get

func (s *TransactionsService) Get(
	ctx context.Context,
	orderID string,
	opts ...RequestOption,
) (*Transaction, error)

Get mencari transaksi berdasarkan trx_id atau reference_id.

func (*TransactionsService) List

List mengambil daftar transaksi beserta pagination.

func (*TransactionsService) Refund

func (s *TransactionsService) Refund(
	ctx context.Context,
	trxID string,
	refundAmount int64,
	reason string,
	opts ...RequestOption,
) (*RefundResult, error)

Refund mengembalikan dana transaksi yang sudah dibayar.

type WalletBalance

type WalletBalance struct {
	Balance   string `json:"balance"`
	Currency  string `json:"currency"`
	Formatted string `json:"formatted"`
}

WalletBalance adalah saldo tersedia.

type WalletService

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

WalletService menangani saldo merchant.

func (*WalletService) Balance

func (s *WalletService) Balance(
	ctx context.Context,
	opts ...RequestOption,
) (*WalletBalance, error)

Balance mengembalikan saldo tersedia.

func (*WalletService) PendingBalance

func (s *WalletService) PendingBalance(
	ctx context.Context,
	opts ...RequestOption,
) (*PendingBalance, error)

PendingBalance mengembalikan saldo dalam kliring.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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