starlingbank

package module
v1.0.0 Latest Latest
Warning

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

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

README

starlingbank-go

A complete, production-grade Go client for the Starling Bank Public API, structured around Domain-Driven Design (DDD) principles.

Unofficial — not affiliated with or endorsed by Starling Bank.

Architecture

The package is organised as a collection of bounded contexts, each a self-contained sub-package with its own domain entities, value objects, and application service:

starlingbank-go/
├── account/          Accounts, identifiers, confirmation of funds
├── accountholder/    Identity, name, address, type, email
├── balance/          Cleared/effective/available balances
├── transaction/      Feed items, spending categories, attachments, statements
├── payment/          Local & international payments, standing orders
├── payee/            Saved recipients and their images
├── directdebit/      Direct Debit mandates
├── savingsgoal/      Savings goals, top-ups, withdrawals, recurring transfers
├── card/             Card controls (freeze, spend limits, channel toggles)
├── webhook/          Event subscriptions and HMAC signature verification
├── oauth/            Authorization URL, code exchange, token refresh
├── receipt/          Itemized receipts and binary attachments
├── merchant/         Merchant and merchant-location enrichment
├── onboarding/       TPP customer onboarding
├── shared/           Shared kernel: Money value object, StarlingTime
└── internal/
    └── transport/    HTTP infrastructure (retry, auth, hooks, errors)
Key DDD patterns applied
Pattern Where
Value Object shared.Money (immutable, equality by value, domain methods Add/Sub/IsZero)
Value Object shared.StarlingTime (robust ISO 8601 unmarshaling)
Typed IDs account.ID, payment.OrderID, savingsgoal.ID, etc. — prevent ID mix-ups at compile time
Entity account.Account, transaction.FeedItem, payee.Payee, etc.
Aggregate savingsgoal.SavingsGoal owns RecurringTransfer; payment.StandingOrder owns Recurrence
Application Service Each bounded context's Service struct
Port (interface) transport.Doer — domain services depend on this abstraction, not on HTTP
Adapter transport.Requester — concrete implementation of Doer
Shared Kernel shared/ — imported by all bounded contexts
Anti-corruption layer internal/transport/ — translates HTTP responses into domain types

Installation

go get github.com/iamkanishka/starlingbank-go

Requires Go 1.22+. Zero required runtime dependencies (stdlib only).

Quick start

import (
    "context"
    "log"

    starlingbank "github.com/iamkanishka/starlingbank-go"
)

client := starlingbank.NewClient(
    starlingbank.WithAccessToken(os.Getenv("STARLING_TOKEN")),
    starlingbank.WithEnvironment(starlingbank.Production),
)

ctx := context.Background()

// List accounts
accounts, err := client.Account.List(ctx)
if err != nil {
    log.Fatal(err)
}

for _, acc := range accounts {
    // Strongly-typed ID — can't accidentally pass a payeeUID here
    bal, err := client.Balance.Get(ctx, acc.AccountID)
    if err != nil {
        log.Fatal(err)
    }
    // Money value object with domain methods
    log.Printf("%s: %s", acc.Name, bal.EffectiveBalance)
}

Services

Field on Client Bounded context Key methods
client.Account account List, Get, Identifiers, ConfirmFunds
client.AccountHolder accountholder Get, GetType, GetName, GetIndividual, GetBusiness, GetAddresses, UpdateAddress, UpdateEmail, GetAuthorisingIndividual
client.Balance balance Get
client.Transaction transaction List, Get, UpdateSpendingCategory, UpdateUserNote, ListAttachments, GetAttachment, StatementPDF, StatementCSV
client.Payment payment PayLocalOnce, PayInternational, GetConversionQuote, ListStandingOrders, GetStandingOrder, CreateOrUpdateStandingOrder, DeleteStandingOrder, ListScheduledPayments
client.Payee payee List, Create, Delete, GetImage
client.DirectDebit directdebit List, Get, Cancel
client.SavingsGoal savingsgoal List, Get, Create, Delete, AddMoney, WithdrawMoney, SetPhoto, GetRecurringTransfer, CreateRecurringTransfer, DeleteRecurringTransfer
client.Card card List, Enable, Disable, GetControls, SetChannelEnabled, SetSpendingLimit, RemoveSpendingLimit
client.Webhook webhook List, VerifySignature
client.OAuth oauth AuthorizeURL, ExchangeCode, RefreshToken
client.Receipt receipt Get, ListForFeedItem, AttachToFeedItem, UploadAttachment, GetAttachment
client.Merchant merchant Get, GetLocation
client.Onboarding onboarding Create, GetStatus

Money value object

// shared.Money is immutable — arithmetic returns new values
price := shared.NewMoney("GBP", 1050)  // £10.50
tax   := shared.NewMoney("GBP", 210)   // £2.10

total, err := price.Add(tax)           // £12.60
fmt.Println(total)                     // "GBP 12.60"
fmt.Println(total.IsZero())            // false
fmt.Println(total.DecimalAmount())     // 12.6

_, err = price.Add(shared.NewMoney("EUR", 100)) // ErrCurrencyMismatch

Typed IDs

// Compile-time safety — you cannot pass a savingsGoalUID where accountID is expected
func (s *Service) Get(ctx context.Context, id account.ID) (*Account, error)

// Build IDs from strings returned by the API
accountID := account.ID(acc.AccountID)

Error handling

import "github.com/iamkanishka/starlingbank-go/internal/transport"

_, err := client.Account.Get(ctx, "uid")
if err != nil {
    var apiErr *transport.APIError
    var netErr *transport.NetworkError

    switch {
    case errors.Is(err, transport.ErrUnauthorized):   // refresh token
    case errors.Is(err, transport.ErrNotFound):       // handle 404
    case errors.Is(err, transport.ErrRateLimited):    // back off
    case errors.As(err, &apiErr):
        log.Printf("API error %s (HTTP %d, request_id=%s): %s",
            apiErr.Code, apiErr.Status, apiErr.RequestID, apiErr.Message)
    case errors.As(err, &netErr):
        log.Printf("Network error: %v", netErr.Cause)
    }
}

Configuration

client := starlingbank.NewClient(
    starlingbank.WithAccessToken("token"),
    starlingbank.WithEnvironment(starlingbank.Sandbox),   // default
    starlingbank.WithTimeout(30 * time.Second),
    starlingbank.WithRetry(transport.RetryConfig{
        MaxAttempts:       3,
        BaseDelay:         250 * time.Millisecond,
        MaxDelay:          4 * time.Second,
        RetryableStatuses: []int{429, 500, 502, 503, 504},
    }),
    starlingbank.WithHook(func(ctx context.Context, event string,
        req *http.Request, resp *http.Response, err error) {
        // logging, metrics, tracing
    }),
)

Testing your own code

Each service depends on transport.Doer, so you can inject a test double without starting a real HTTP server:

type mockDoer struct{ ... }
func (m *mockDoer) Get(ctx context.Context, path string, q url.Values, out any) error { ... }
// ... implement remaining methods

svc := account.NewService(&mockDoer{...})

Or use net/http/httptest as the integration tests in this package demonstrate.

Development

go test ./... -race -count=1
go vet ./...
golangci-lint run ./...

License

MIT

Documentation

Overview

Package starlingbank is a complete, production-grade Go client for the Starling Bank Public API, structured around Domain-Driven Design (DDD) principles.

Architecture

The package is organized into bounded contexts, each as a self-contained sub-package:

  • account — accounts, identifiers, confirmation of funds
  • accountholder — identity, name, address, type, email
  • balance — cleared/effective/available balances
  • transaction — feed items, spending category, attachments, statements
  • payment — local, international, and standing order payments
  • payee — saved recipients and their images
  • directdebit — Direct Debit mandates
  • savingsgoal — savings goals, top-ups, withdrawals, recurring transfers
  • card — card controls (freeze, spend limits, channel toggles)
  • webhook — event subscriptions and HMAC signature verification
  • oauth — authorization URL, code exchange, token refresh
  • receipt — itemized receipts and binary attachments
  • merchant — merchant and merchant-location enrichment
  • onboarding — TPP customer onboarding

Each bounded context exposes a typed Service with methods named after domain operations (not HTTP verbs). Services depend on the transport.Doer interface, enabling full unit-test isolation without a real HTTP server.

Quick start

client := starlingbank.NewClient(
    starlingbank.WithAccessToken("your-token"),
    starlingbank.WithEnvironment(starlingbank.Production),
)

accounts, err := client.Account.List(ctx)

Error handling

All methods return nil or a typed error — either transport.APIError (HTTP failures) or transport.NetworkError (transport failures). Use errors.As to inspect them, or compare against the sentinel values transport.ErrUnauthorized, transport.ErrNotFound, etc.

Hooks

Register transport.HookFunc callbacks via WithHook for logging, Prometheus metrics, or OpenTelemetry spans — with no build-time dependency on those libraries.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// Account manages bank accounts and their identifiers.
	Account *account.Service
	// AccountHolder manages the identity and address of the account holder.
	AccountHolder *accountholder.Service
	// Balance provides balance enquiries for an account.
	Balance *balance.Service
	// Transaction provides the transaction feed, spending categories, and statements.
	Transaction *transaction.Service
	// Payment initiates local and international payments and manages standing orders.
	Payment *payment.Service
	// Payee manages saved payment recipients.
	Payee *payee.Service
	// DirectDebit manages Direct Debit mandates.
	DirectDebit *directdebit.Service
	// SavingsGoal manages savings pots and their top-up/withdrawal transfers.
	SavingsGoal *savingsgoal.Service
	// Card manages card controls (freeze, spend limits, channel toggles).
	Card *card.Service
	// Webhook provides webhook subscription listing and signature verification.
	Webhook *webhook.Service
	// OAuth implements the OAuth 2.0 authorization code flow.
	OAuth *oauth.Service
	// Receipt manages itemized receipts and binary receipt attachments.
	Receipt *receipt.Service
	// Merchant provides merchant and merchant-location enrichment data.
	Merchant *merchant.Service
	// Onboarding handles TPP customer onboarding applications.
	Onboarding *onboarding.Service
}

Client is the entry point for all Starling Bank API calls. Obtain one with NewClient; it is safe for concurrent use by multiple goroutines.

Each field is the application service for its bounded context. All services share a single underlying HTTP transport and configuration.

func NewClient

func NewClient(opts ...ClientOption) *Client

NewClient creates a new Client with the given options. Supply at least WithAccessToken for authenticated calls.

Example:

c := starlingbank.NewClient(
    starlingbank.WithAccessToken(os.Getenv("STARLING_TOKEN")),
    starlingbank.WithEnvironment(starlingbank.Production),
    starlingbank.WithHook(myLoggingHook),
)

type ClientOption

type ClientOption func(*clientConfig)

ClientOption is a functional option for NewClient.

func WithAccessToken

func WithAccessToken(token string) ClientOption

WithAccessToken sets the Bearer token used for API authentication.

func WithBaseURL

func WithBaseURL(url string) ClientOption

WithBaseURL overrides the API base URL (useful for tests and proxies).

func WithEnvironment

func WithEnvironment(env Environment) ClientOption

WithEnvironment selects Sandbox or Production.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) ClientOption

WithHTTPClient replaces the underlying *http.Client entirely.

func WithHook

func WithHook(fn transport.HookFunc) ClientOption

WithHook registers a transport.HookFunc called before and after every request. Multiple hooks are called in registration order.

func WithNoRetry

func WithNoRetry() ClientOption

WithNoRetry disables the built-in retry logic.

func WithRetry

func WithRetry(r transport.RetryConfig) ClientOption

WithRetry configures retry behavior.

func WithTimeout

func WithTimeout(d time.Duration) ClientOption

WithTimeout sets the per-request HTTP timeout.

func WithTransport

func WithTransport(t http.RoundTripper) ClientOption

WithTransport replaces only the http.Transport, keeping the configured timeout.

func WithUserAgent

func WithUserAgent(ua string) ClientOption

WithUserAgent overrides the User-Agent header.

type Environment

type Environment int

Environment selects which Starling API environment to target.

const (
	// Sandbox targets https://api-sandbox.starlingbank.com (default).
	Sandbox Environment = iota
	// Production targets https://api.starlingbank.com.
	Production
)

Directories

Path Synopsis
Package account defines the Account bounded context: entities, value objects, and the application service for managing Starling bank accounts.
Package account defines the Account bounded context: entities, value objects, and the application service for managing Starling bank accounts.
Package accountholder defines the Account Holder bounded context: the identity, address, and personal/business details of a Starling account owner.
Package accountholder defines the Account Holder bounded context: the identity, address, and personal/business details of a Starling account owner.
Package balance defines the Balance bounded context.
Package balance defines the Balance bounded context.
Package card defines the Card bounded context: payment card entities and card control value objects.
Package card defines the Card bounded context: payment card entities and card control value objects.
Package directdebit defines the Direct Debit bounded context: mandates authorising third parties to collect payments from a Starling account.
Package directdebit defines the Direct Debit bounded context: mandates authorising third parties to collect payments from a Starling account.
internal
transport
Package transport provides the HTTP infrastructure layer for the Starling Bank client.
Package transport provides the HTTP infrastructure layer for the Starling Bank client.
Package merchant defines the Merchant bounded context: enriched merchant and merchant-location data linked to card transactions.
Package merchant defines the Merchant bounded context: enriched merchant and merchant-location data linked to card transactions.
Package oauth implements the Starling Bank OAuth 2.0 authorization code flow.
Package oauth implements the Starling Bank OAuth 2.0 authorization code flow.
Package onboarding defines the Customer Onboarding bounded context, used by registered Third-Party Providers to onboard new customers onto Starling.
Package onboarding defines the Customer Onboarding bounded context, used by registered Third-Party Providers to onboard new customers onto Starling.
Package payee defines the Payee bounded context: saved payment recipients.
Package payee defines the Payee bounded context: saved payment recipients.
Package payment defines the Payment bounded context: local (FPS) payments, international payments, and standing orders.
Package payment defines the Payment bounded context: local (FPS) payments, international payments, and standing orders.
Package receipt defines the Receipt bounded context: itemized receipts and binary receipt attachments linked to transaction feed items.
Package receipt defines the Receipt bounded context: itemized receipts and binary receipt attachments linked to transaction feed items.
Package savingsgoal defines the Savings Goal bounded context: savings pots, top-up transfers, withdrawals, and recurring transfer schedules.
Package savingsgoal defines the Savings Goal bounded context: savings pots, top-up transfers, withdrawals, and recurring transfer schedules.
Package shared defines value objects and primitive types that form the shared kernel across all bounded contexts in the Starling Bank domain.
Package shared defines value objects and primitive types that form the shared kernel across all bounded contexts in the Starling Bank domain.
Package transaction defines the Transaction Feed bounded context: feed items, spending categories, attachments, and statement downloads.
Package transaction defines the Transaction Feed bounded context: feed items, spending categories, attachments, and statement downloads.
Package webhook defines the Webhook bounded context: event subscriptions and the domain event envelope delivered by Starling's push notification system.
Package webhook defines the Webhook bounded context: event subscriptions and the domain event envelope delivered by Starling's push notification system.

Jump to

Keyboard shortcuts

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