opensettle

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: May 14, 2026 License: MIT Imports: 14 Imported by: 0

README

OpenSettle Go SDK

Go Reference

Official Go SDK for the OpenSettle API — stablecoin billing on Base, Ethereum, Polygon, Arbitrum, Solana, and Tron. Non-custodial: OpenSettle never holds your funds.

Hand-written, zero third-party runtime dependencies, idiomatic context.Context throughout, typed errors reachable with errors.As, signed-webhook verifier in a separate sub-package.

Install

go get github.com/OpenSettle/opensettle-sdk-go

Requires Go 1.22+.

Quick start

package main

import (
    "context"
    "log"
    "os"

    opensettle "github.com/OpenSettle/opensettle-sdk-go"
)

func main() {
    client, err := opensettle.NewClient(
        os.Getenv("OPENSETTLE_KEY"),        // sk_test_... or sk_live_...
        os.Getenv("OPENSETTLE_WORKSPACE"),
        opensettle.WithTestMode(os.Getenv("ENV") != "production"),
    )
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()
    checkout, err := client.Checkouts.Create(ctx, opensettle.CreateCheckoutRequest{
        Mode:       opensettle.CheckoutPayment,
        CustomerID: "cu_1",
        InvoiceID:  "in_1",
        SuccessURL: "https://example.com/thanks",
    })
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("checkout %s, expires %s", checkout.ID, checkout.ExpiresAt)
}

Resources

The SDK mirrors the OpenSettle REST API one-to-one:

Field Endpoint
client.Checkouts /v1/workspaces/<ws>/checkouts
client.Customers /v1/workspaces/<ws>/customers
client.Invoices /v1/workspaces/<ws>/invoices
client.Payments /v1/workspaces/<ws>/payments
client.Products /v1/workspaces/<ws>/products (+ prices)
client.Subscriptions /v1/workspaces/<ws>/subscriptions
client.WebhookEndpoints /v1/workspaces/<ws>/webhook_endpoints

Every method takes ctx context.Context as the first argument, returns (*ResultType, error), and propagates request IDs in error values.

Typed errors

checkout, err := client.Payments.Refund(ctx, paymentID, opensettle.InitiateRefundRequest{})
if err != nil {
    var rl *opensettle.RateLimitError
    if errors.As(err, &rl) {
        time.Sleep(time.Duration(rl.RetryAfter) * time.Second)
        return retry()
    }
    var stepUp *opensettle.StepUpRequiredError
    if errors.As(err, &stepUp) {
        return promptStepUp()
    }
    return err
}

Every API error code in the platform's 13-code taxonomy maps to a concrete Go type:

Error type Codes
*InvalidRequestError invalid_request
*InvalidStateTransitionError invalid_state_transition
*AuthenticationError unauthorized
*ForbiddenError forbidden
*NotFoundError not_found
*ConflictError conflict
*RateLimitError (.RetryAfter) rate_limited
*SettlementError chain_reverted, insufficient_confirmations, signing_required
*StepUpRequiredError aal_required
*APIError internal_error and unknown codes
*NetworkError transport-layer failures

OpenSettleError is the embedded base; all subtypes carry Code, Status, RequestID, and Param.

Webhooks

Verification lives in a sub-package so consumers can use it without dragging the rest of the SDK into their handler:

import "github.com/OpenSettle/opensettle-sdk-go/webhooks"

func handle(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    v, err := webhooks.Verify(webhooks.Opts{
        RawBody:         body,
        SignatureHeader: r.Header.Get("x-opensettle-signature"),
        Secret:          os.Getenv("OPENSETTLE_WEBHOOK_SECRET"),
    })
    if err != nil {
        http.Error(w, "invalid", http.StatusBadRequest)
        return
    }
    process(v.Body, v.Timestamp)
}

webhooks.Decode[T] is the generic version when you want a typed event:

ev, _, err := webhooks.Decode[PaymentConfirmedEvent](opts)

Signature scheme: HMAC-SHA256 over <unix_seconds>.<raw_body>, hex-encoded. Constant-time comparison via hmac.Equal. Default tolerance window is 5 minutes; tune via Opts.Tolerance.

Configuration

client, err := opensettle.NewClient(apiKey, workspaceID,
    opensettle.WithBaseURL("https://api.opensettle.io"),
    opensettle.WithHTTPClient(myHTTPClient),
    opensettle.WithMaxRetries(3),       // default 3; set 0 to disable
    opensettle.WithTimeout(30 * time.Second),
    opensettle.WithTestMode(true),      // refuses sk_live_ keys; CI circuit breaker
    opensettle.WithUserAgent("my-app/1.0"),
)

Retries cover 5xx + 429 + transport errors with exponential backoff capped at 4 s. The SDK respects Retry-After (both delta-seconds and HTTP-date forms). Idempotency keys are automatically attached to money-adjacent writes and shared across retry attempts.

Versioning

Strict semver. The major version tracks the HTTP API major version (v1). Minor versions add features without breakage; patch versions are bug fixes only. See CHANGELOG.md.

License

MIT

Documentation

Overview

Package opensettle is the official Go SDK for the OpenSettle API.

OpenSettle is a non-custodial stablecoin billing platform: USDC and USDT subscriptions, one-shot checkouts, and invoices on Base, Ethereum, Polygon, Arbitrum, Solana, and Tron.

Quick start

import "github.com/OpenSettle/opensettle-sdk-go"

client, err := opensettle.NewClient(
    os.Getenv("OPENSETTLE_KEY"),
    os.Getenv("OPENSETTLE_WORKSPACE"),
    opensettle.WithTestMode(os.Getenv("ENV") != "production"),
)
if err != nil { log.Fatal(err) }

checkout, err := client.Checkouts.Create(ctx, opensettle.CreateCheckoutRequest{ /* ... */ })

Typed errors

Every API error is mapped to a typed value reachable via errors.As:

if _, err := client.Payments.Refund(ctx, paymentID, req); err != nil {
    var rl *opensettle.RateLimitError
    if errors.As(err, &rl) {
        time.Sleep(time.Duration(rl.RetryAfter) * time.Second)
        return retry()
    }
    var settle *opensettle.SettlementError
    if errors.As(err, &settle) && settle.Code == opensettle.CodeSigningRequired {
        return promptCustomerToReapprove()
    }
    return err
}

Webhooks

Webhook signature verification lives in the sub-package github.com/OpenSettle/opensettle-sdk-go/webhooks so consumers can use it without dragging the full SDK into their webhook handler.

Index

Constants

View Source
const Version = "0.3.0"

Version is the SDK release tag this build was cut from. It is sent as part of the User-Agent header on every request so the API can break out adoption by SDK version.

Variables

This section is empty.

Functions

func FromEnvelope

func FromEnvelope(body []byte, status int, retryAfter float64) error

FromEnvelope maps a parsed envelope + HTTP status to the right typed error. Unknown codes fall back to *APIError so a new server-side code can't crash older SDKs.

retryAfter is the parsed Retry-After header value (seconds); 0 means the server didn't send one.

func IsOpenSettleError

func IsOpenSettleError(err error) bool

IsOpenSettleError reports whether err is or wraps an *OpenSettleError. Convenience around errors.As for the broad case.

func WaitFor added in v0.3.0

func WaitFor[T any](
	ctx context.Context,
	retrieve func(ctx context.Context, id string) (T, error),
	resourceID string,
	until func(T) bool,
	opts WaitOptions,
) (T, error)

WaitFor polls retrieve(ctx, id) every opts.Interval until until(r) returns true, then returns the resource. Returns *WaitTimeoutError when opts.Timeout elapses first, or the wrapped ctx error on cancellation. Any error returned by retrieve aborts the loop immediately.

Type parameter T is the concrete resource pointed at by Retrieve (e.g. *Payment, *Invoice).

Types

type APIError

type APIError struct{ *OpenSettleError }

func (*APIError) Unwrap

func (e *APIError) Unwrap() error

type AuthenticationError

type AuthenticationError struct{ *OpenSettleError }

func (*AuthenticationError) Unwrap

func (e *AuthenticationError) Unwrap() error

type AutopayMode

type AutopayMode string
const (
	AutopayAllowance   AutopayMode = "allowance"
	AutopaySmartWallet AutopayMode = "smart-wallet"
	AutopayManual      AutopayMode = "manual"
)

type CancelMode

type CancelMode string

CancelMode controls whether cancellation is immediate or deferred to the next billing boundary.

const (
	CancelImmediately CancelMode = "immediately"
	CancelAtPeriodEnd CancelMode = "at_period_end"
)

type CancelSubscriptionRequest

type CancelSubscriptionRequest struct {
	Reason string     `json:"reason,omitempty"`
	Mode   CancelMode `json:"mode,omitempty"`
}

type ChainId

type ChainId string

ChainId is a supported settlement chain. Mirrors `ChainId` in `@opensettle/shared/schemas/wallet`.

const (
	ChainBase     ChainId = "base"
	ChainEthereum ChainId = "ethereum"
	ChainPolygon  ChainId = "polygon"
	ChainArbitrum ChainId = "arbitrum"
	ChainTron     ChainId = "tron"
	ChainSolana   ChainId = "solana"
)

type ChangePlanRequest

type ChangePlanRequest struct {
	PriceID       string        `json:"priceId"`
	ProrationMode ProrationMode `json:"prorationMode,omitempty"`
}

type Checkout

type Checkout struct {
	ID          string         `json:"id"`
	WorkspaceID string         `json:"workspaceId"`
	Mode        CheckoutMode   `json:"mode"`
	Status      CheckoutStatus `json:"status"`
	CustomerID  string         `json:"customerId"`
	InvoiceID   *string        `json:"invoiceId"`
	PriceID     *string        `json:"priceId"`
	AmountMinor int            `json:"amountMinor"`
	Currency    string         `json:"currency"`
	Chain       ChainId        `json:"chain"`
	Token       TokenSymbol    `json:"token"`
	Description *string        `json:"description"`
	SuccessURL  string         `json:"successUrl"`
	CancelURL   *string        `json:"cancelUrl"`
	ExpiresAt   string         `json:"expiresAt"`
	CompletedAt *string        `json:"completedAt"`
	Metadata    Metadata       `json:"metadata"`
	CreatedAt   string         `json:"createdAt"`
	// HostedURL is a relative URL path (e.g. "/checkout/<hostedToken>");
	// concatenate with the web origin (e.g. "https://opensettle.io"+HostedURL)
	// to get the buyer-facing redirect URL.
	HostedURL string `json:"hostedUrl"`
}

type CheckoutMode

type CheckoutMode string
const (
	CheckoutPayment      CheckoutMode = "payment"
	CheckoutSubscription CheckoutMode = "subscription"
)

type CheckoutStatus

type CheckoutStatus string
const (
	CheckoutOpen      CheckoutStatus = "open"
	CheckoutPending   CheckoutStatus = "pending"
	CheckoutSucceeded CheckoutStatus = "succeeded"
	CheckoutFailed    CheckoutStatus = "failed"
	CheckoutExpired   CheckoutStatus = "expired"
)

type CheckoutsResource

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

CheckoutsResource exposes /v1/workspaces/<ws>/checkouts.

func (*CheckoutsResource) Create

Create starts a hosted checkout session. Body is required; the request is sent with an auto-generated Idempotency-Key to make retries safe.

func (*CheckoutsResource) Retrieve

func (r *CheckoutsResource) Retrieve(ctx context.Context, id string) (*Checkout, error)

Retrieve fetches a checkout session by id.

type Client

type Client struct {
	Checkouts        *CheckoutsResource
	Customers        *CustomersResource
	Invoices         *InvoicesResource
	Payments         *PaymentsResource
	Products         *ProductsResource
	Subscriptions    *SubscriptionsResource
	WebhookEndpoints *WebhookEndpointsResource
	// contains filtered or unexported fields
}

Client is the top-level handle. One per workspace. Safe for concurrent use by multiple goroutines.

func NewClient

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

NewClient builds a Client. apiKey must start with sk_live_ or sk_test_; workspaceID is the merchant's workspace (required on every route).

type ConfigError

type ConfigError struct{ Message string }

ConfigError is returned by NewClient when the caller's config is internally inconsistent (e.g. test-mode with a live key). Kept distinct from API-side errors so callers don't have to know they need a transport before hitting an obvious config bug.

func (*ConfigError) Error

func (e *ConfigError) Error() string

type ConflictError

type ConflictError struct{ *OpenSettleError }

func (*ConflictError) Unwrap

func (e *ConflictError) Unwrap() error

type CreateCheckoutRequest

type CreateCheckoutRequest struct {
	Mode             CheckoutMode `json:"mode"`
	CustomerID       string       `json:"customerId,omitempty"`
	CustomerEmail    string       `json:"customerEmail,omitempty"`
	CustomerName     string       `json:"customerName,omitempty"`
	InvoiceID        string       `json:"invoiceId,omitempty"`
	PriceID          string       `json:"priceId,omitempty"`
	SuccessURL       string       `json:"successUrl"`
	CancelURL        string       `json:"cancelUrl,omitempty"`
	Chain            ChainId      `json:"chain,omitempty"`
	Token            TokenSymbol  `json:"token,omitempty"`
	ExpiresInMinutes int          `json:"expiresInMinutes,omitempty"`
	Metadata         Metadata     `json:"metadata,omitempty"`
}

type CreateCustomerRequest

type CreateCustomerRequest struct {
	Email    string   `json:"email"`
	Name     string   `json:"name,omitempty"`
	Wallet   string   `json:"wallet,omitempty"`
	Country  string   `json:"country,omitempty"`
	Metadata Metadata `json:"metadata,omitempty"`
}

type CreateInvoiceRequest

type CreateInvoiceRequest struct {
	CustomerID     string      `json:"customerId"`
	Chain          ChainId     `json:"chain"`
	Token          TokenSymbol `json:"token"`
	Currency       string      `json:"currency,omitempty"`
	LineItems      []LineItem  `json:"lineItems"`
	Memo           string      `json:"memo,omitempty"`
	DueInDays      int         `json:"dueInDays,omitempty"`
	SubscriptionID string      `json:"subscriptionId,omitempty"`
	Metadata       Metadata    `json:"metadata,omitempty"`
}

type CreatePriceRequest

type CreatePriceRequest struct {
	Amount   int           `json:"amount"`
	Currency string        `json:"currency,omitempty"`
	Interval PriceInterval `json:"interval"`
	Metadata Metadata      `json:"metadata,omitempty"`
}

type CreateProductRequest

type CreateProductRequest struct {
	Name        string   `json:"name"`
	Description string   `json:"description,omitempty"`
	Metadata    Metadata `json:"metadata,omitempty"`
}

type CreateSubscriptionRequest

type CreateSubscriptionRequest struct {
	CustomerID string      `json:"customerId"`
	PriceID    string      `json:"priceId"`
	Chain      ChainId     `json:"chain"`
	Token      TokenSymbol `json:"token"`
	Autopay    AutopayMode `json:"autopay,omitempty"`
	TrialDays  int         `json:"trialDays,omitempty"`
	Metadata   Metadata    `json:"metadata,omitempty"`
}

type CreateWebhookEndpointRequest

type CreateWebhookEndpointRequest struct {
	URL         string   `json:"url"`
	Description string   `json:"description,omitempty"`
	Events      []string `json:"events,omitempty"`
}

type CreateWebhookEndpointResponse

type CreateWebhookEndpointResponse struct {
	Endpoint      WebhookEndpoint `json:"endpoint"`
	SigningSecret string          `json:"signingSecret"`
}

type CursorPage

type CursorPage[T any] struct {
	Data       []T    `json:"data"`
	NextCursor string `json:"nextCursor"`
	HasMore    bool   `json:"hasMore,omitempty"`
}

CursorPage wraps a paginated list response. The API returns a cursor envelope around every listed collection.

type Customer

type Customer struct {
	ID                  string         `json:"id"`
	WorkspaceID         string         `json:"workspaceId"`
	Email               string         `json:"email"`
	Name                string         `json:"name"`
	Wallet              *string        `json:"wallet"`
	Country             *string        `json:"country"`
	Status              CustomerStatus `json:"status"`
	ActiveSubscriptions int            `json:"activeSubscriptions"`
	LifetimeValue       int            `json:"lifetimeValue"`
	Metadata            Metadata       `json:"metadata"`
	CreatedAt           string         `json:"createdAt"`
	DeletedAt           *string        `json:"deletedAt"`
}

type CustomerStatus

type CustomerStatus string
const (
	CustomerActive  CustomerStatus = "active"
	CustomerAtRisk  CustomerStatus = "at_risk"
	CustomerChurned CustomerStatus = "churned"
)

type CustomersResource

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

CustomersResource exposes /v1/workspaces/<ws>/customers.

func (*CustomersResource) Create

Create makes a new customer. Auto-attaches an Idempotency-Key.

func (*CustomersResource) Delete

func (r *CustomersResource) Delete(ctx context.Context, customerID string) error

Delete is a soft-delete: PII is scrubbed but historical references continue to resolve.

func (*CustomersResource) List

List returns a cursor-paginated page of customers.

func (*CustomersResource) ListIter added in v0.3.0

func (r *CustomersResource) ListIter(ctx context.Context, query *ListCustomersQuery) *Iter[Customer]

ListIter returns a cursor-driven iterator over all customers matching the query. Auto-fetches subsequent pages.

it := c.Customers.ListIter(ctx, &opensettle.ListCustomersQuery{Status: opensettle.CustomerActive})
for it.Next() { fmt.Println(it.Item().ID) }
if err := it.Err(); err != nil { … }

func (*CustomersResource) Retrieve

func (r *CustomersResource) Retrieve(ctx context.Context, customerID string) (*Customer, error)

Retrieve fetches a customer by id.

func (*CustomersResource) Update

func (r *CustomersResource) Update(ctx context.Context, customerID string, input UpdateCustomerRequest) (*Customer, error)

Update applies a partial update.

type ErrorCode

type ErrorCode string

ErrorCode is the API's stable error taxonomy. Values mirror `packages/sdk/src/errors.ts` exactly.

const (
	CodeInvalidRequest            ErrorCode = "invalid_request"
	CodeInvalidStateTransition    ErrorCode = "invalid_state_transition"
	CodeUnauthorized              ErrorCode = "unauthorized"
	CodeForbidden                 ErrorCode = "forbidden"
	CodeNotFound                  ErrorCode = "not_found"
	CodeConflict                  ErrorCode = "conflict"
	CodeRateLimited               ErrorCode = "rate_limited"
	CodeInternalError             ErrorCode = "internal_error"
	CodeChainReverted             ErrorCode = "chain_reverted"
	CodeInsufficientConfirmations ErrorCode = "insufficient_confirmations"
	CodeSigningRequired           ErrorCode = "signing_required"
	CodeAALRequired               ErrorCode = "aal_required"
	CodeNetworkError              ErrorCode = "network_error"
)

type ForbiddenError

type ForbiddenError struct{ *OpenSettleError }

func (*ForbiddenError) Unwrap

func (e *ForbiddenError) Unwrap() error

type InitiateRefundRequest

type InitiateRefundRequest struct {
	AmountMinor      int    `json:"amountMinor,omitempty"`
	Reason           string `json:"reason,omitempty"`
	RecipientAddress string `json:"recipientAddress,omitempty"`
}

type InitiateRefundResponse

type InitiateRefundResponse struct {
	Payment    Payment            `json:"payment"`
	UnsignedTx UnsignedTxEnvelope `json:"unsignedTx"`
}

type InvalidRequestError

type InvalidRequestError struct{ *OpenSettleError }

func (*InvalidRequestError) Unwrap

func (e *InvalidRequestError) Unwrap() error

type InvalidStateTransitionError

type InvalidStateTransitionError struct{ *OpenSettleError }

func (*InvalidStateTransitionError) Unwrap

func (e *InvalidStateTransitionError) Unwrap() error

type Invoice

type Invoice struct {
	ID             string        `json:"id"`
	WorkspaceID    string        `json:"workspaceId"`
	Number         string        `json:"number"`
	CustomerID     string        `json:"customerId"`
	SubscriptionID *string       `json:"subscriptionId"`
	AmountMinor    int           `json:"amountMinor"`
	Currency       string        `json:"currency"`
	Chain          ChainId       `json:"chain"`
	Token          TokenSymbol   `json:"token"`
	Status         InvoiceStatus `json:"status"`
	LineItems      []LineItem    `json:"lineItems"`
	Memo           *string       `json:"memo"`
	PaymentID      *string       `json:"paymentId"`
	HostedURL      string        `json:"hostedUrl"`
	IssuedAt       *string       `json:"issuedAt"`
	DueAt          string        `json:"dueAt"`
	PaidAt         *string       `json:"paidAt"`
	VoidedAt       *string       `json:"voidedAt"`
	Metadata       Metadata      `json:"metadata"`
	CreatedAt      string        `json:"createdAt"`
}

type InvoiceStatus

type InvoiceStatus string
const (
	InvoiceDraft   InvoiceStatus = "draft"
	InvoiceOpen    InvoiceStatus = "open"
	InvoicePaid    InvoiceStatus = "paid"
	InvoicePastDue InvoiceStatus = "past_due"
	InvoiceVoid    InvoiceStatus = "void"
)

type InvoicesResource

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

InvoicesResource exposes /v1/workspaces/<ws>/invoices.

func (*InvoicesResource) Create

func (*InvoicesResource) List

func (*InvoicesResource) ListIter added in v0.3.0

func (r *InvoicesResource) ListIter(ctx context.Context, query *ListInvoicesQuery) *Iter[Invoice]

ListIter returns a cursor-driven iterator over all invoices matching the query.

func (*InvoicesResource) Remind

func (r *InvoicesResource) Remind(ctx context.Context, invoiceID string) (*Invoice, error)

Remind re-sends a reminder for an unpaid invoice.

func (*InvoicesResource) Retrieve

func (r *InvoicesResource) Retrieve(ctx context.Context, invoiceID string) (*Invoice, error)

func (*InvoicesResource) Send

func (r *InvoicesResource) Send(ctx context.Context, invoiceID string) (*Invoice, error)

Send emails the hosted invoice link to the customer.

func (*InvoicesResource) Void

func (r *InvoicesResource) Void(ctx context.Context, invoiceID string) (*Invoice, error)

Void marks an unpaid invoice as void. Terminal state.

type Iter added in v0.3.0

type Iter[T any] struct {
	// contains filtered or unexported fields
}

Iter is a cursor-driven iterator over a paginated API resource. It auto-fetches the next page when the current page is drained and stops when the server signals hasMore=false.

Resource List methods continue to return a single page for backward compatibility; iterators are returned by separate ListIter (or Iter-suffixed) methods on each resource — see the resource files.

Usage:

it := c.Customers.ListIter(ctx, &opensettle.ListCustomersQuery{Status: opensettle.CustomerActive})
for it.Next() {
    fmt.Println(it.Item().ID)
}
if err := it.Err(); err != nil { … }

func (*Iter[T]) Err added in v0.3.0

func (it *Iter[T]) Err() error

Err returns any error that stopped the iteration. Nil on a clean end.

func (*Iter[T]) Item added in v0.3.0

func (it *Iter[T]) Item() *T

Item returns the most-recently-yielded item. Only valid after Next has returned true.

func (*Iter[T]) Next added in v0.3.0

func (it *Iter[T]) Next() bool

Next advances the iterator. Returns false when the iteration is exhausted (call Err to distinguish "natural end" from "error").

type LineItem

type LineItem struct {
	Description     string `json:"description"`
	Quantity        int    `json:"quantity"`
	UnitAmountMinor int    `json:"unitAmountMinor"`
}

type ListCustomersQuery

type ListCustomersQuery struct {
	Status CustomerStatus
	Q      string
	Cursor string
	Limit  int
}

type ListInvoicesQuery

type ListInvoicesQuery struct {
	Cursor     string
	Limit      int
	CustomerID string
	Status     InvoiceStatus
}

type ListPaymentsQuery

type ListPaymentsQuery struct {
	Cursor     string
	Limit      int
	CustomerID string
	Status     PaymentStatus
}

type ListProductsQuery

type ListProductsQuery struct {
	Cursor string
	Limit  int
	Active *bool
}

type ListSubscriptionsQuery

type ListSubscriptionsQuery struct {
	Cursor     string
	Limit      int
	CustomerID string
	Status     SubscriptionStatus
}

type Metadata

type Metadata map[string]any

Metadata is the free-form key/value blob attached to most resources. Values are arbitrary JSON; Go callers can marshal whatever the API accepts on their side. Nil = no metadata.

type NetworkError

type NetworkError struct{ *OpenSettleError }

func (*NetworkError) Unwrap

func (e *NetworkError) Unwrap() error

type NotFoundError

type NotFoundError struct{ *OpenSettleError }

func (*NotFoundError) Unwrap

func (e *NotFoundError) Unwrap() error

type OpenSettleError

type OpenSettleError struct {
	Code      ErrorCode
	Message   string
	Status    int
	RequestID string
	Param     string
}

OpenSettleError is the base type. Every concrete error in this package embeds it, so callers can either match the broad type via errors.As(err, &*OpenSettleError{}) or branch on the specific subtype.

func (*OpenSettleError) Error

func (e *OpenSettleError) Error() string

type Option

type Option func(*clientConfig)

Option configures a Client. Use NewClient(...).

func WithBaseURL

func WithBaseURL(url string) Option

WithBaseURL overrides the API host. Defaults to https://api.opensettle.io.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient replaces the underlying *http.Client. Useful for injecting custom transports, proxies, or mocks. The SDK still applies its own retry and timeout logic on top.

func WithMaxRetries

func WithMaxRetries(n int) Option

WithMaxRetries sets the retry budget for transient failures (5xx, 429, transport errors). Default 3. Set 0 to disable retries entirely.

func WithTestMode

func WithTestMode(test bool) Option

WithTestMode asserts the apiKey environment matches. With true, the SDK refuses sk_live_… keys; with false it refuses sk_test_…. Useful as a circuit breaker in CI. Default is unasserted (either accepted).

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the per-request timeout. Default 30s.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent appends a caller-supplied product token to the SDK's User-Agent. The default is `opensettle-go/<Version>`; with this option the header becomes `opensettle-go/<Version> <userAgent>`.

type Payment

type Payment struct {
	ID                string        `json:"id"`
	WorkspaceID       string        `json:"workspaceId"`
	CustomerID        *string       `json:"customerId"`
	SubscriptionID    *string       `json:"subscriptionId"`
	InvoiceID         *string       `json:"invoiceId"`
	WalletID          *string       `json:"walletId"`
	AmountMinor       int           `json:"amountMinor"`
	FeeMinor          int           `json:"feeMinor"`
	NetMinor          int           `json:"netMinor"`
	Currency          string        `json:"currency"`
	Token             TokenSymbol   `json:"token"`
	Chain             ChainId       `json:"chain"`
	Status            PaymentStatus `json:"status"`
	FailureReason     *string       `json:"failureReason"`
	Description       *string       `json:"description"`
	TxHash            *string       `json:"txHash"`
	BlockNumber       *int          `json:"blockNumber"`
	Confirmations     int           `json:"confirmations"`
	RefundTxHash      *string       `json:"refundTxHash"`
	RefundAmountMinor *int          `json:"refundAmountMinor"`
	RefundBroadcastAt *string       `json:"refundBroadcastAt"`
	RefundedAt        *string       `json:"refundedAt"`
	RefundReason      *string       `json:"refundReason"`
	CreatedAt         string        `json:"createdAt"`
	ConfirmedAt       *string       `json:"confirmedAt"`
}

type PaymentStatus

type PaymentStatus string
const (
	PaymentPending   PaymentStatus = "pending"
	PaymentConfirmed PaymentStatus = "confirmed"
	PaymentFailed    PaymentStatus = "failed"
	PaymentRefunded  PaymentStatus = "refunded"
	PaymentReorged   PaymentStatus = "reorged"
)

type PaymentsResource

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

PaymentsResource exposes /v1/workspaces/<ws>/payments.

func (*PaymentsResource) List

func (*PaymentsResource) ListIter added in v0.3.0

func (r *PaymentsResource) ListIter(ctx context.Context, query *ListPaymentsQuery) *Iter[Payment]

ListIter returns a cursor-driven iterator over all payments matching the query.

func (*PaymentsResource) Refund

Refund initiates a refund. Returns a multi-key envelope {payment, unsignedTx} — the merchant's wallet signs unsignedTx and broadcasts it; OpenSettle never holds funds.

Step-up auth (AAL=2) is required on this route, surfaced as *StepUpRequiredError for API-key callers. Sessions get through if they re-authed within freshWithinSeconds.

func (*PaymentsResource) RefundBroadcast

func (r *PaymentsResource) RefundBroadcast(ctx context.Context, paymentID string, input RecordRefundBroadcastRequest) (*Payment, error)

RefundBroadcast tells OpenSettle the merchant has signed and broadcast the refund tx. The chain reader picks it up and flips status to refunded once it confirms.

func (*PaymentsResource) Retrieve

func (r *PaymentsResource) Retrieve(ctx context.Context, paymentID string) (*Payment, error)

type Price

type Price struct {
	ID          string        `json:"id"`
	WorkspaceID string        `json:"workspaceId"`
	ProductID   string        `json:"productId"`
	Amount      int           `json:"amount"`
	Currency    string        `json:"currency"`
	Interval    PriceInterval `json:"interval"`
	Active      bool          `json:"active"`
	Metadata    Metadata      `json:"metadata"`
	CreatedAt   string        `json:"createdAt"`
}

type PriceInterval

type PriceInterval string
const (
	PriceOneTime PriceInterval = "one_time"
	PriceWeek    PriceInterval = "week"
	PriceMonth   PriceInterval = "month"
	PriceYear    PriceInterval = "year"
)

type Product

type Product struct {
	ID          string   `json:"id"`
	WorkspaceID string   `json:"workspaceId"`
	Name        string   `json:"name"`
	Description *string  `json:"description"`
	Active      bool     `json:"active"`
	Metadata    Metadata `json:"metadata"`
	CreatedAt   string   `json:"createdAt"`
}

type ProductsResource

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

ProductsResource exposes /v1/workspaces/<ws>/products and the nested /prices collection.

func (*ProductsResource) Create

func (*ProductsResource) CreatePrice

func (r *ProductsResource) CreatePrice(ctx context.Context, productID string, input CreatePriceRequest) (*Price, error)

CreatePrice attaches a new price to a product.

func (*ProductsResource) Delete

func (r *ProductsResource) Delete(ctx context.Context, productID string) error

Delete is a hard-delete. Returns *ConflictError (409) if any subscription still references the product.

func (*ProductsResource) DeletePrice

func (r *ProductsResource) DeletePrice(ctx context.Context, priceID string) error

DeletePrice hard-deletes a price. Returns *ConflictError (409) if any subscription still references it.

func (*ProductsResource) List

func (*ProductsResource) ListIter added in v0.3.0

func (r *ProductsResource) ListIter(ctx context.Context, query *ListProductsQuery) *Iter[Product]

ListIter returns a cursor-driven iterator over all products matching the query.

func (*ProductsResource) ListPrices

func (r *ProductsResource) ListPrices(ctx context.Context, productID string) ([]Price, error)

ListPrices returns the prices attached to a product.

func (*ProductsResource) Retrieve

func (r *ProductsResource) Retrieve(ctx context.Context, productID string) (*Product, error)

func (*ProductsResource) Update

func (r *ProductsResource) Update(ctx context.Context, productID string, input UpdateProductRequest) (*Product, error)

type ProrationMode

type ProrationMode string

ProrationMode controls when a plan change takes effect.

const (
	ProrationImmediately ProrationMode = "immediately"
	ProrationAtPeriodEnd ProrationMode = "at_period_end"
)

type RateLimitError

type RateLimitError struct {
	*OpenSettleError
	RetryAfter float64
}

RateLimitError carries the optional Retry-After hint advertised by the API. Value is in seconds. A zero RetryAfter means the server didn't advertise one — caller should fall back to its own backoff.

func (*RateLimitError) Unwrap

func (e *RateLimitError) Unwrap() error

type RecordRefundBroadcastRequest

type RecordRefundBroadcastRequest struct {
	RefundTxHash string `json:"refundTxHash"`
}

type RotateWebhookSecretRequest

type RotateWebhookSecretRequest struct {
	GraceSeconds int `json:"graceSeconds,omitempty"`
}

type RotateWebhookSecretResponse deprecated

type RotateWebhookSecretResponse = CreateWebhookEndpointResponse

RotateWebhookSecretResponse is now an alias for CreateWebhookEndpointResponse — the rotate endpoint returns the same {endpoint, signingSecret} envelope as create.

Deprecated: use *CreateWebhookEndpointResponse directly. This alias will be removed in a future release.

type SettlementError

type SettlementError struct{ *OpenSettleError }

func (*SettlementError) Unwrap

func (e *SettlementError) Unwrap() error

type StepUpRequiredError

type StepUpRequiredError struct{ *OpenSettleError }

func (*StepUpRequiredError) Unwrap

func (e *StepUpRequiredError) Unwrap() error

type Subscription

type Subscription struct {
	ID                 string             `json:"id"`
	WorkspaceID        string             `json:"workspaceId"`
	CustomerID         string             `json:"customerId"`
	ProductID          string             `json:"productId"`
	PriceID            string             `json:"priceId"`
	AmountMinor        int                `json:"amountMinor"`
	Currency           string             `json:"currency"`
	Chain              ChainId            `json:"chain"`
	Token              TokenSymbol        `json:"token"`
	Status             SubscriptionStatus `json:"status"`
	Autopay            AutopayMode        `json:"autopay"`
	AllowanceTx        *string            `json:"allowanceTx"`
	AllowanceRemaining *int               `json:"allowanceRemaining"`
	TrialEndsAt        *string            `json:"trialEndsAt"`
	StartedAt          string             `json:"startedAt"`
	CurrentPeriodEnd   string             `json:"currentPeriodEnd"`
	NextBillingDate    string             `json:"nextBillingDate"`
	CanceledAt         *string            `json:"canceledAt"`
	CancelReason       *string            `json:"cancelReason"`
	PausedAt           *string            `json:"pausedAt"`
	MRRMinor           int                `json:"mrrMinor"`
	Metadata           Metadata           `json:"metadata"`
	CreatedAt          string             `json:"createdAt"`
}

type SubscriptionStatus

type SubscriptionStatus string
const (
	SubTrialing SubscriptionStatus = "trialing"
	SubActive   SubscriptionStatus = "active"
	SubPastDue  SubscriptionStatus = "past_due"
	SubPaused   SubscriptionStatus = "paused"
	SubCanceled SubscriptionStatus = "canceled"
)

type SubscriptionsResource

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

SubscriptionsResource exposes /v1/workspaces/<ws>/subscriptions.

func (*SubscriptionsResource) Cancel

Cancel ends a subscription. Mode controls timing (immediately vs at_period_end). Default is at_period_end when input.Mode is empty. Reason is recorded on the audit log.

func (*SubscriptionsResource) ChangePlan

func (r *SubscriptionsResource) ChangePlan(ctx context.Context, subID string, input ChangePlanRequest) (*Subscription, error)

ChangePlan swaps the subscription to a new price. ProrationMode controls whether the customer is billed immediately for the delta or at the next period boundary.

func (*SubscriptionsResource) Create

func (*SubscriptionsResource) List

func (*SubscriptionsResource) ListIter added in v0.3.0

ListIter returns a cursor-driven iterator over all subscriptions matching the query.

func (*SubscriptionsResource) Pause

func (r *SubscriptionsResource) Pause(ctx context.Context, subID string) (*Subscription, error)

func (*SubscriptionsResource) Resume

func (r *SubscriptionsResource) Resume(ctx context.Context, subID string) (*Subscription, error)

func (*SubscriptionsResource) Retrieve

func (r *SubscriptionsResource) Retrieve(ctx context.Context, subID string) (*Subscription, error)

type TestWebhookEndpointRequest

type TestWebhookEndpointRequest struct {
	EventType string `json:"eventType"`
}

type TestWebhookEndpointResponse

type TestWebhookEndpointResponse struct {
	OK        bool `json:"ok"`
	Status    int  `json:"status"`
	LatencyMs int  `json:"latencyMs"`
}

type TokenSymbol

type TokenSymbol string

TokenSymbol is a supported stablecoin. The platform settles only in USDC and USDT.

const (
	TokenUSDC TokenSymbol = "USDC"
	TokenUSDT TokenSymbol = "USDT"
)

type UnsignedEvmTx

type UnsignedEvmTx struct {
	To              string `json:"to"`
	Data            string `json:"data"`
	Value           string `json:"value"`
	ChainID         int    `json:"chainId"`
	TokenAddress    string `json:"tokenAddress"`
	Recipient       string `json:"recipient"`
	AmountBaseUnits string `json:"amountBaseUnits"`
}

type UnsignedTxEnvelope

type UnsignedTxEnvelope struct {
	Chain        ChainId        `json:"chain"`
	Token        TokenSymbol    `json:"token"`
	To           string         `json:"to"`
	AmountMinor  int            `json:"amountMinor"`
	Memo         string         `json:"memo,omitempty"`
	Instructions string         `json:"instructions"`
	EVM          *UnsignedEvmTx `json:"evm,omitempty"`
}

type UpdateCustomerRequest

type UpdateCustomerRequest struct {
	Name     *string  `json:"name,omitempty"`
	Wallet   *string  `json:"wallet,omitempty"`
	Country  *string  `json:"country,omitempty"`
	Metadata Metadata `json:"metadata,omitempty"`
}

type UpdateProductRequest

type UpdateProductRequest struct {
	Name        *string  `json:"name,omitempty"`
	Description *string  `json:"description,omitempty"`
	Active      *bool    `json:"active,omitempty"`
	Metadata    Metadata `json:"metadata,omitempty"`
}

type UpdateWebhookEndpointRequest

type UpdateWebhookEndpointRequest struct {
	URL         *string                `json:"url,omitempty"`
	Description *string                `json:"description,omitempty"`
	Events      []string               `json:"events,omitempty"`
	Status      *WebhookEndpointStatus `json:"status,omitempty"`
}

type WaitOptions added in v0.3.0

type WaitOptions struct {
	// Hard timeout. Defaults to 2 minutes when zero.
	Timeout time.Duration
	// Poll interval. Defaults to 2 seconds when zero.
	Interval time.Duration
	// contains filtered or unexported fields
}

WaitOptions tunes polling behaviour.

type WaitTimeoutError added in v0.3.0

type WaitTimeoutError struct {
	ResourceID string
	Timeout    time.Duration
	// Last is the most-recently-observed resource (typed as the
	// concrete *T that the Retrieve closure returns).
	Last any
}

WaitTimeoutError is returned when the target state is not reached before the timeout elapses. It carries the last-observed resource as an opaque any value — type-assert to the expected pointer type to inspect it.

func (*WaitTimeoutError) Error added in v0.3.0

func (e *WaitTimeoutError) Error() string

type WebhookEndpoint

type WebhookEndpoint struct {
	ID                 string                `json:"id"`
	WorkspaceID        string                `json:"workspaceId"`
	URL                string                `json:"url"`
	Description        *string               `json:"description"`
	Events             []string              `json:"events"`
	Status             WebhookEndpointStatus `json:"status"`
	SuccessRate        float64               `json:"successRate"`
	RotationGraceUntil *string               `json:"rotationGraceUntil"`
	CreatedAt          string                `json:"createdAt"`
}

type WebhookEndpointStatus

type WebhookEndpointStatus string
const (
	WebhookEnabled  WebhookEndpointStatus = "enabled"
	WebhookDisabled WebhookEndpointStatus = "disabled"
)

type WebhookEndpointsResource

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

WebhookEndpointsResource exposes /v1/workspaces/<ws>/webhook_endpoints.

func (*WebhookEndpointsResource) Create

Create makes a new endpoint. The response includes the plaintext signing secret exactly once — store it immediately. Multi-key envelope {endpoint, signingSecret} preserved.

func (*WebhookEndpointsResource) Delete

func (r *WebhookEndpointsResource) Delete(ctx context.Context, endpointID string) error

func (*WebhookEndpointsResource) List

List returns every webhook endpoint configured for the workspace. The endpoint is small enough that the API doesn't paginate.

func (*WebhookEndpointsResource) Retrieve

func (r *WebhookEndpointsResource) Retrieve(ctx context.Context, endpointID string) (*WebhookEndpoint, error)

func (*WebhookEndpointsResource) RotateSecret

RotateSecret rotates the signing secret. Returns the same {endpoint, signingSecret} envelope as Create — store SigningSecret immediately. Step-up auth (AAL=2) required; API-key callers receive *StepUpRequiredError.

func (*WebhookEndpointsResource) Test

Test fires a sample event at the endpoint synchronously to verify wiring. The returned status is the response status the endpoint returned to OpenSettle.

func (*WebhookEndpointsResource) Update

Directories

Path Synopsis
Package webhooks verifies signed OpenSettle webhook deliveries.
Package webhooks verifies signed OpenSettle webhook deliveries.

Jump to

Keyboard shortcuts

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