increase

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 3 Imported by: 0

README

increase-go

A production-grade, independent Go client for the Increase API — banking-as-a-service for accounts, ACH/wire/check/RTP/FedNow transfers, cards, entities, and more.

This is a from-scratch implementation with a hexagonal/DDD architecture, built to match the standards of Increase's public API surface (all ~90 resource groups, ~240 operations). It has zero external dependencies — only the Go standard library.

Usage

package main

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

	"github.com/iamkanishka/increase-go"
	"github.com/iamkanishka/increase-go/domain"
)

func main() {
	client := increase.New(
		increase.WithAPIKey(os.Getenv("INCREASE_API_KEY")),
		increase.WithEnvironment(increase.SandboxEnvironment),
	)

	ctx := context.Background()

	account, err := client.Accounts.Create(ctx, domain.AccountCreateParams{
		Name: "My First Account",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("created", account.ID)

	// Lazy, cursor-based pagination — pages are fetched on demand as
	// the iterator is consumed, not all up front.
	iter := client.Accounts.ListAutoPaging(ctx, domain.AccountListParams{})
	for iter.Next(ctx) {
		fmt.Println(iter.Current().ID, iter.Current().Name)
	}
	if err := iter.Err(); err != nil {
		log.Fatal(err)
	}

	// Sandbox-only simulations let you drive objects through their
	// lifecycle without waiting on real banking rails.
	transfer, err := client.ACHTransfers.Create(ctx, domain.ACHTransferCreateParams{
		AccountID:           account.ID,
		Amount:              1000,
		StatementDescriptor: "Test payment",
	})
	if err != nil {
		log.Fatal(err)
	}
	if _, err := client.Simulations.ACHTransfers.Submit(ctx, transfer.ID); err != nil {
		log.Fatal(err)
	}
}
Error handling
_, err := client.Accounts.Get(ctx, "account_does_not_exist")
if increase.IsNotFound(err) {
	// ...
}

var apiErr *increase.Error
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.Type, apiErr.Title, apiErr.Status, apiErr.Detail)
}
Webhooks
body, _ := io.ReadAll(r.Body)
if err := webhook.Verify(body, r.Header, signingSecret, webhook.Options{}); err != nil {
	http.Error(w, "invalid signature", http.StatusBadRequest)
	return
}
var event map[string]any
json.Unmarshal(body, &event)
Retries and idempotency

WithMaxRetries (default 2) retries rate-limited (429) and server-error (5xx/408/409) responses with exponential backoff and jitter, honoring Retry-After when present. Because retrying a POST/PATCH naively could double-create something, the transport generates an Idempotency-Key once before the first attempt and reuses it across every retry of that request — Increase guarantees replaying the same key returns the original result.

Logging
client := increase.New(
	increase.WithAPIKey(apiKey),
	increase.WithLogger(slog.Default()),
)

Emits structured events for request start, completion (status, duration, attempt count), retries, and terminal failures.

Design notes

  • Nullability: response fields Increase documents as nullable are Go pointers (*string, *time.Time, ...); everything else is a plain value. Optional request parameters are pointers with omitempty; required parameters are plain values.
  • Enums: modeled as named string types with an IsKnown() method, since Increase may add new enum values over time — check IsKnown() before treating an unrecognized value as an error.
  • Pagination: every List method returns a *pagination.Page[T], and every resource also has a ListAutoPaging method returning a lazy *pagination.Iterator[T] that only fetches the next page when the current one is exhausted.
  • File uploads: client.Files.Create is the one method that sends multipart/form-data instead of JSON, since it uploads raw bytes.

Provenance

Domain models and endpoint definitions were derived from Increase's published API surface (cross-referenced against Increase's official Go SDK for field-level accuracy) and reimplemented from scratch in this hexagonal architecture — this is an independent client, not a fork.

Testing

go test ./...          # all packages
go test ./... -race     # with the race detector

Covers: webhook signature verification (valid/invalid/tampered/stale/multi-signature), lazy pagination (page-boundary laziness, error propagation), the HTTP transport (retry/backoff, non-retryable errors, idempotency key stability across retries, caller-supplied idempotency keys, nested query encoding, context cancellation), and end-to-end resource behavior against httptest servers (create/get/update, 404 → IsNotFound, multi-page auto-pagination, simulations wiring, and nullable/optional field JSON semantics across multiple resources).

Documentation

Overview

Package increase is an independent, hexagonal/DDD-architecture Go client for the Increase API (https://increase.com) — banking-as-a- service for accounts, ACH/wire/check/RTP/FedNow transfers, cards, entities, and more.

client := increase.New(increase.WithAPIKey("sandbox_..."))
account, err := client.Accounts.Get(ctx, "account_in71c4amph0vgo2qllky")

Architecture

This file is the only one in the root directory. Everything it exports is implemented in layered subpackages, following domain-driven design:

domain/                 Entities, value objects, enums, and
                        request/response types for every resource.
                        Pure data — no behavior, no HTTP awareness.
ports/                  The hexagonal boundary: Transport is the one
                        interface every resource service depends on;
                        HTTPDoer is the seam the default HTTP adapter
                        depends on.
application/            The use-case layer: Client and one *XService
                        per resource (AccountService, CardService,
                        ...), each a thin wrapper over ports.Transport.
internal/infrastructure/transport/  The default ports.Transport
                        adapter: net/http with automatic retries,
                        idempotency-key injection, and structured
                        log/slog logging.
internal/infrastructure/apierror/   Decodes Increase's API error
                        response shape.
pagination/             Generic, lazy cursor pagination (Page[T],
                        Iterator[T]), used by every List method.
webhook/                Standard Webhooks signature verification.

Resource services and domain types never import net/http directly; they depend only on ports.Transport, so the default adapter can be swapped out (for testing, instrumentation, or a different transport entirely) without touching any business logic.

This package (increase) is a thin, stable facade over application: it re-exports Client, New, every functional option, and the error types and helpers, so callers only ever need to import "github.com/iamkanishka/increase-go" and "github.com/iamkanishka/increase-go/domain" regardless of how the implementation beneath is organized.

Index

Constants

View Source
const (
	SandboxEnvironment    = application.SandboxEnvironment
	ProductionEnvironment = application.ProductionEnvironment
)

Variables

This section is empty.

Functions

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err is an API error representing a 404 response — for example, retrieving an object by an ID that doesn't exist or that this API key can't access.

func IsRateLimited

func IsRateLimited(err error) bool

IsRateLimited reports whether err is an API error representing a 429 response. The client already retries these automatically (see WithMaxRetries); this is useful if you've disabled retries or want to react to rate limiting yourself.

Types

type Client

type Client = application.Client

Client is the entry point for the Increase API. Construct one with New. Every resource is a field on Client, grouped the same way Increase's API documentation groups them — client.Accounts, client.ACHTransfers, client.Cards, and so on — plus client.Simulations for the sandbox-only simulation endpoints.

func New

func New(opts ...Option) *Client

New builds a Client. With no options, it reads INCREASE_API_KEY from the environment and talks to the sandbox environment.

client := increase.New(
	increase.WithAPIKey(os.Getenv("INCREASE_API_KEY")),
	increase.WithEnvironment(increase.ProductionEnvironment),
)

type Environment

type Environment = application.Environment

Environment selects which of Increase's environments requests are sent to.

type Error

type Error = application.Error

Error represents an error returned by the Increase API itself — as opposed to a transport-level failure like a timeout — following the error shape documented at https://increase.com/documentation/api#errors.

Use errors.As to recover one from a call's returned error:

_, err := client.Accounts.Close(ctx, "account_with_balance")
var apiErr *increase.Error
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.Type, apiErr.Status)
}

func AsAPIError

func AsAPIError(err error) (*Error, bool)

AsAPIError extracts an *Error from err, if it is (or wraps) one.

type FieldError

type FieldError = application.FieldError

FieldError describes a single validation problem attributed to one request parameter.

type Option

type Option = application.Option

Option configures a Client. Pass any number of these to New.

func WithAPIKey

func WithAPIKey(apiKey string) Option

WithAPIKey sets the API key used to authenticate every request. If not provided, New falls back to the INCREASE_API_KEY environment variable.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL overrides the API base URL entirely, useful for testing against a local mock server. Takes precedence over WithEnvironment.

func WithEnvironment

func WithEnvironment(env Environment) Option

WithEnvironment selects sandbox or production. Defaults to sandbox. WithBaseURL takes precedence if both are set.

func WithHTTPClient

func WithHTTPClient(client ports.HTTPDoer) Option

WithHTTPClient substitutes the underlying HTTP client. The provided client only needs to satisfy Do(*http.Request) (*http.Response, error) — see ports.HTTPDoer — so custom RoundTrippers, instrumentation wrappers, or test doubles all work here.

func WithHeader

func WithHeader(key, value string) Option

WithHeader sets an additional header sent with every request. Can be called multiple times to set multiple headers.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger attaches a *slog.Logger that receives structured events for every outgoing request: start, completion (with status and duration), retries, and terminal failures. By default no logging is performed.

func WithMaxRetries

func WithMaxRetries(n int) Option

WithMaxRetries sets how many times a request is retried after a retryable failure (rate limiting, server errors, or transient network failures) before giving up. Defaults to 2. Pass 0 to disable retries.

This is safe for POST/PATCH requests specifically because the client automatically attaches an Idempotency-Key to any mutating request that doesn't already have one, generated once before the first attempt and reused for every retry — Increase guarantees that retrying a request with the same key returns the original result rather than creating a duplicate.

Directories

Path Synopsis
Package application is the application layer (use-case / service layer) of increase-go: it defines Client and one *XService per Increase resource, each a thin, strongly-typed wrapper over the ports.Transport port.
Package application is the application layer (use-case / service layer) of increase-go: it defines Client and one *XService per Increase resource, each a thin, strongly-typed wrapper over the ports.Transport port.
Package domain models Increase API resources and requests: entities, value objects, enums, and the request/response DTOs every resource service in the application package accepts and returns.
Package domain models Increase API resources and requests: entities, value objects, enums, and the request/response DTOs every resource service in the application package accepts and returns.
internal
infrastructure/apierror
Package apierror defines the shape of errors returned by the Increase API and how they're decoded from an HTTP response body.
Package apierror defines the shape of errors returned by the Increase API and how they're decoded from an HTTP response body.
infrastructure/transport
Package transport contains the default infrastructure adapter for the ports.Transport interface: an HTTP client that talks to the Increase API over the network, with automatic retries, idempotency-key injection for retried mutating requests, and structured logging via log/slog.
Package transport contains the default infrastructure adapter for the ports.Transport interface: an HTTP client that talks to the Increase API over the network, with automatic retries, idempotency-key injection for retried mutating requests, and structured logging via log/slog.
Package pagination provides a generic, lazy cursor-based paginator used by every List method across this SDK.
Package pagination provides a generic, lazy cursor-based paginator used by every List method across this SDK.
Package ports defines the boundaries (hexagonal "ports") between the application layer of this SDK — the per-resource services in the root increase package, which implement Increase's business operations — and the infrastructure that actually moves bytes over the network.
Package ports defines the boundaries (hexagonal "ports") between the application layer of this SDK — the per-resource services in the root increase package, which implement Increase's business operations — and the infrastructure that actually moves bytes over the network.
Package webhook verifies the authenticity of incoming webhook requests from Increase.
Package webhook verifies the authenticity of incoming webhook requests from Increase.

Jump to

Keyboard shortcuts

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