Skip to main content
The official billing.io SDK for Go 1.21+. Zero external dependencies — uses only the standard library.

Go Package

github.com/billing-io/billing-go

GitHub

billing-io/billing-go

Installation

go get github.com/billing-io/billing-go

Quick Start

package main

import (
	"context"
	"fmt"

	billingio "github.com/billing-io/billing-go"
)

func main() {
	client := billingio.New("sk_live_...")

	checkout, err := client.Checkouts.Create(context.Background(), billingio.CreateCheckoutParams{
		AmountUSD: 49.99,
		Chain:     "tron",
		Token:     "USDT",
		Metadata: map[string]string{
			"order_id": "ord_12345",
		},
	})
	if err != nil {
		panic(err)
	}

	fmt.Println(checkout.CheckoutID)
	fmt.Println(checkout.DepositAddress)
}

Create a Checkout

checkout, err := client.Checkouts.Create(ctx, billingio.CreateCheckoutParams{
	AmountUSD: 100.00,
	Chain:     "arbitrum",
	Token:     "USDC",
	Metadata: map[string]string{
		"customer_email": "alice@example.com",
	},
})

List with Auto-Pagination

The SDK provides an iterator for automatic cursor-based pagination:
iter := client.Checkouts.List(ctx, billingio.ListParams{Limit: 25})

for iter.Next() {
	checkout := iter.Current()
	fmt.Println(checkout.CheckoutID, checkout.Status)
}
if err := iter.Err(); err != nil {
	// handle error
}
Or fetch a single page:
page, err := client.Checkouts.ListPage(ctx, billingio.ListParams{Limit: 10})

for _, checkout := range page.Data {
	fmt.Println(checkout.CheckoutID)
}

Get Checkout Status

status, err := client.Checkouts.GetStatus(ctx, "chk_abc123")

fmt.Println(status.Status)                // "confirming"
fmt.Println(status.Confirmations)          // 8
fmt.Println(status.RequiredConfirmations)  // 19

Webhook Signature Verification

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

	isValid := billingio.VerifyWebhookSignature(
		string(body),
		r.Header.Get("X-Billing-Signature"),
		"whsec_...",
	)

	if !isValid {
		http.Error(w, "Invalid signature", http.StatusUnauthorized)
		return
	}

	// process event...
	w.WriteHeader(http.StatusOK)
}

Error Handling

The SDK provides typed error helpers:
checkout, err := client.Checkouts.Create(ctx, params)
if err != nil {
	if billingio.IsNotFound(err) {
		// 404 - resource not found
	} else if billingio.IsRateLimited(err) {
		// 429 - back off and retry
	} else if billingio.IsAuthError(err) {
		// 401 - check API key
	}
	return err
}
All API errors are returned as *billingio.Error:
var apiErr *billingio.Error
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.Status)  // 422
	fmt.Println(apiErr.Code)    // "validation_error"
	fmt.Println(apiErr.Message) // "amount_usd must be positive"
}

Customers

customer, err := client.Customers.Create(ctx, billingio.CreateCustomerParams{
	Email:    "alice@example.com",
	Name:     "Alice Johnson",
	Metadata: map[string]string{"plan": "pro"},
})

customer, err := client.Customers.Get(ctx, "cus_abc123")

updated, err := client.Customers.Update(ctx, "cus_abc123", billingio.UpdateCustomerParams{
	Name: "Alice Smith",
})

iter := client.Customers.List(ctx, billingio.ListParams{Limit: 25})
for iter.Next() {
	fmt.Println(iter.Current().Email)
}

Payment Methods

pm, err := client.PaymentMethods.Create(ctx, billingio.CreatePaymentMethodParams{
	Chain:       "tron",
	Token:       "USDT",
	DisplayName: "Primary USDT",
})

err = client.PaymentMethods.SetDefault(ctx, "pm_abc123")

iter := client.PaymentMethods.List(ctx, billingio.ListParams{Limit: 10})
for iter.Next() {
	pm := iter.Current()
	fmt.Println(pm.DisplayName, pm.Chain, pm.Token)
}
link, err := client.PaymentLinks.Create(ctx, billingio.CreatePaymentLinkParams{
	AmountUSD:   99.99,
	Chain:       "arbitrum",
	Token:       "USDC",
	Description: "Annual subscription",
})
fmt.Println(link.URL)

Subscriptions

plan, err := client.SubscriptionPlans.Create(ctx, billingio.CreateSubscriptionPlanParams{
	Name:      "Pro Monthly",
	AmountUSD: 29.99,
	Interval:  "monthly",
	Token:     "USDT",
	Chain:     "tron",
})

sub, err := client.Subscriptions.Create(ctx, billingio.CreateSubscriptionParams{
	CustomerID:      "cus_abc123",
	PlanID:          plan.ID,
	PaymentMethodID: "pm_abc123",
})

// Cancel
_, err = client.Subscriptions.Update(ctx, "sub_abc123", billingio.UpdateSubscriptionParams{
	Status: "canceled",
})

// List renewals
iter := client.SubscriptionRenewals.List(ctx, billingio.ListSubscriptionRenewalsParams{
	SubscriptionID: "sub_abc123",
})
for iter.Next() {
	r := iter.Current()
	fmt.Println(r.Status, r.AmountUSD)
}

Entitlements

ent, err := client.Entitlements.Create(ctx, billingio.CreateEntitlementParams{
	PlanID:       "plan_abc123",
	FeatureKey:   "api_calls",
	ValueType:    "numeric",
	ValueNumeric: 10000,
})

check, err := client.Entitlements.Check(ctx, billingio.CheckEntitlementParams{
	CustomerID: "cus_abc123",
	FeatureKey: "api_calls",
})
fmt.Println(check.HasAccess, check.Value)

Payouts

payout, err := client.PayoutIntents.Create(ctx, billingio.CreatePayoutIntentParams{
	RecipientAddress: "TXyz...",
	Chain:            "tron",
	Token:            "USDT",
	Amount:           500.00,
	Currency:         "USD",
})

// Submit tx hash after executing externally
err = client.PayoutIntents.Execute(ctx, "po_abc123", billingio.ExecutePayoutParams{
	TxHash: "0xabc...",
})

// List settlements
iter := client.Settlements.List(ctx, billingio.ListParams{Limit: 25})
for iter.Next() {
	s := iter.Current()
	fmt.Println(s.TxHash, s.ConfirmedAt)
}

Revenue

iter := client.RevenueEvents.List(ctx, billingio.ListParams{Limit: 25})
for iter.Next() {
	e := iter.Current()
	fmt.Println(e.EventType, e.Amount, e.Currency)
}

adj, err := client.Adjustments.Create(ctx, billingio.CreateAdjustmentParams{
	Type:        "credit",
	AmountUSD:   10.00,
	Description: "Loyalty discount",
	CustomerID:  "cus_abc123",
})

Context Support

All methods accept a context.Context for cancellation and timeouts:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

checkout, err := client.Checkouts.Create(ctx, params)