unit

package module
v1.0.0 Latest Latest
Warning

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

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

README

unit-go

A complete, production-grade Go client for the Unit embedded banking API — applications, customers, accounts, cards, payments, transactions, counterparties, repayments, recurring payments, check deposits, check payments, stop payments, chargebacks, statements, webhooks, events, tokens, institutions, authorizations, and sandbox simulation.

Zero runtime dependencies. Standard library only.

Design

unit-go follows a domain-driven design. Each of Unit's 20 API surface areas is its own bounded-context package under domain/, with its own entities, value objects, and a Service interface + implementation:

unit-go/
├── unit.go                  # root Client facade wiring every bounded context together
├── shared/                  # shared kernel: Money, Address, FullName, Phone, Tags, Relationship
├── telemetry/                # request lifecycle instrumentation hooks
├── internal/
│   ├── transport/            # HTTP client: auth, retry/backoff, idempotency, pagination
│   └── jsonapi/               # JSON:API envelope encode/decode (anti-corruption layer)
└── domain/
    ├── application/           # KYC/KYB onboarding applications
    ├── customer/                # customers, authorized users
    ├── account/                  # deposit accounts, limits, balance history
    ├── card/                       # debit/credit, individual/business, virtual/physical
    ├── payment/                     # ACH, wire, book, bulk payments
    ├── transaction/                   # the transaction ledger
    ├── counterparty/                    # saved external bank accounts
    ├── repayment/                         # book/ACH credit repayments
    ├── recurringpayment/                    # scheduled recurring payments/repayments
    ├── checkdeposit/                          # mobile check deposit
    ├── checkpayment/                            # print-and-mail check payments
    ├── stoppayment/                                # ACH/check stop payment orders
    ├── chargeback/                                   # card transaction disputes
    ├── statement/                                      # account statements (HTML/PDF)
    ├── webhook/                                          # webhook subscriptions + signature verification
    ├── event/                                              # the 90-day event log
    ├── token/                                                # customer/cardholder/org tokens, 2FA
    ├── institution/                                            # routing number lookup
    ├── authorization/                                            # pending card authorizations
    └── sandbox/                                                    # sandbox event simulation

Every domain Service is an interface, so any part of Client is independently mockable in tests without touching the rest.

Install

go get github.com/iamkanishka/unit-go

Usage

package main

import (
	"context"
	"fmt"
	"log"

	unit "github.com/iamkanishka/unit-go"
	"github.com/iamkanishka/unit-go/domain/account"
	"github.com/iamkanishka/unit-go/domain/payment"
	"github.com/iamkanishka/unit-go/shared"
)

func main() {
	client, err := unit.New(unit.Config{
		Token: "your-unit-api-token",
		// BaseURL defaults to Unit's sandbox host; use "https://api.unit.co" in production.
	})
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()

	acc, err := client.Accounts.CreateDeposit(ctx, account.CreateDepositParams{
		CustomerID:     "cus_123",
		DepositProduct: "checking",
		Name:           "Primary Checking",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(acc.ID, acc.Balance)

	payment, err := client.Payments.CreateACH(ctx, payment.CreateACHParams{
		AccountID:      acc.ID,
		CounterpartyID: "cp_456",
		Amount:         shared.MoneyFromDollars(150.00),
		Direction:      "Credit",
		Description:    "Vendor payment",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(payment.ID, payment.Status)
}
Pagination

List calls return the first page plus a lazy *transport.Paginator[T]:

items, paginator, err := client.Transactions.List(ctx, transaction.ListQuery{AccountID: acc.ID, Limit: 100})
for paginator.HasNext() {
	next, err := paginator.Next(ctx)
	if err != nil {
		log.Fatal(err)
	}
	items = append(items, next...)
}
// or, to drain everything at once:
// all, err := paginator.All(ctx)
Errors

Every failed call returns *unit.Error (an alias for the transport error type), which exposes the HTTP status, Unit's request ID, the JSON:API error objects, and whether the failure was retryable:

_, err := client.Accounts.Get(ctx, "does-not-exist")
var apiErr *unit.Error
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.StatusCode, apiErr.Code(), apiErr.RequestID)
}
Retries

Every request automatically retries on 429 and 5xx responses (and on bare transport failures) with exponential backoff and jitter, honoring Retry-After when Unit sends it. Configure or disable this:

client, err := unit.New(unit.Config{
	Token: token,
	RetryPolicy: &unit.RetryPolicy{MaxAttempts: 2, BaseDelay: 100 * time.Millisecond, MaxDelay: time.Second, Jitter: 0.3},
})
// or: RetryPolicy: unitPtr(unit.NoRetry())
Idempotency

POST/PATCH requests get an auto-generated Idempotency-Key header when the caller doesn't supply one, so accidental retries never double-submit a payment. Supply your own for calls you want to control explicitly (e.g. a key derived from your own transaction ID):

client.Payments.CreateACH(ctx, payment.CreateACHParams{..., IdempotencyKey: "order-8842"})
Telemetry

Every request emits start/stop/retry/exception events through an injectable telemetry.Handler, for wiring into your metrics or logging stack:

client, err := unit.New(unit.Config{
	Token: token,
	Telemetry: telemetry.HandlerFunc(func(ctx context.Context, e telemetry.Event) {
		metrics.Observe(e.Type, e.Method, e.Path, e.StatusCode, e.Duration)
	}),
})
Webhook signature verification
if !webhook.VerifySignatureSHA512(rawBody, r.Header.Get("X-Unit-Signature"), signingKey) {
	http.Error(w, "invalid signature", http.StatusUnauthorized)
	return
}

VerifySignatureSHA1 is also available for webhook subscriptions still on Unit's legacy signing scheme.

Testing this package

go build ./...
go vet ./...
gofmt -l .          # should print nothing
go test ./... -race -cover

The test suite runs entirely against net/http/httptest fake servers — no network access or live Unit credentials required.

A note on field coverage

Resource attribute sets here reflect Unit's well-documented, stable API shapes as of this package's construction. Unit's OpenAPI spec is the source of truth for exact field names and any newly added attributes; if you hit a field this package doesn't expose yet, it's straightforward to extend the relevant domain/<context> package's attribute struct — the JSON:API decode plumbing in internal/jsonapi and internal/transport doesn't need to change.

License

MIT

Documentation

Overview

Package unit is a complete, production-grade Go client for the Unit (unit.co) embedded banking API. It follows a domain-driven design: each bounded context (applications, customers, accounts, cards, payments, transactions, counterparties, repayments, recurring payments, check deposits, check payments, stop payments, chargebacks, statements, webhooks, events, tokens, institutions, authorizations, sandbox) is its own package under domain/, built on the shared transport and JSON:API infrastructure in internal/.

Construction is always explicit -- there is no global client or package level state:

client, err := unit.New(unit.Config{Token: os.Getenv("UNIT_TOKEN")})
if err != nil {
	log.Fatal(err)
}
acc, err := client.Accounts.Get(ctx, "12345")

For production, set Config.BaseURL to "https://api.unit.co"; the default points at Unit's sandbox host.

Index

Constants

View Source
const DefaultBaseURL = transport.DefaultBaseURL

DefaultBaseURL is Unit's sandbox API host.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	Applications      application.Service
	Customers         customer.Service
	Accounts          account.Service
	Cards             card.Service
	Payments          payment.Service
	Transactions      transaction.Service
	Counterparties    counterparty.Service
	Repayments        repayment.Service
	RecurringPayments recurringpayment.Service
	CheckDeposits     checkdeposit.Service
	CheckPayments     checkpayment.Service
	StopPayments      stoppayment.Service
	Chargebacks       chargeback.Service
	Statements        statement.Service
	Webhooks          webhook.Service
	Events            event.Service
	Tokens            token.Service
	Institutions      institution.Service
	Authorizations    authorization.Service
	Sandbox           sandbox.Service
	// contains filtered or unexported fields
}

Client is the complete Unit API surface, organized as one field per bounded context. Every field is a Service interface, which makes each context independently mockable in tests -- callers needing to unit test code that depends on, say, Client.Accounts can substitute a fake account.Service without touching the rest of Client.

func New

func New(cfg Config) (*Client, error)

New constructs a fully wired Client from Config. Config.Token is required; every other field has a sane default (see transport.Config).

type Config

type Config = transport.Config

Config configures a Client. See transport.Config for field docs.

type Error

type Error = transport.Error

Error is the typed error returned for every failed API call. See transport.Error for field docs.

type RetryPolicy

type RetryPolicy = transport.RetryPolicy

RetryPolicy configures automatic retry behaviour. See transport.RetryPolicy for field docs.

func DefaultRetryPolicy

func DefaultRetryPolicy() RetryPolicy

DefaultRetryPolicy returns unit-go's default exponential-backoff retry policy (see transport.DefaultRetryPolicy).

func NoRetry

func NoRetry() RetryPolicy

NoRetry returns a RetryPolicy that disables automatic retries.

Directories

Path Synopsis
domain
account
Package account is the Accounts bounded context: deposit account lifecycle (create, freeze/unfreeze, close), limits, and balance history.
Package account is the Accounts bounded context: deposit account lifecycle (create, freeze/unfreeze, close), limits, and balance history.
application
Package application is the Applications bounded context: creating and tracking individual (KYC) and business (KYB) onboarding applications, and uploading supporting documents.
Package application is the Applications bounded context: creating and tracking individual (KYC) and business (KYB) onboarding applications, and uploading supporting documents.
authorization
Package authorization is the Authorizations bounded context: reading pending card authorizations, which settle into purchaseTransactions or are reversed if declined/expired.
Package authorization is the Authorizations bounded context: reading pending card authorizations, which settle into purchaseTransactions or are reversed if declined/expired.
card
Package card is the Cards bounded context: issuing individual/business, debit/credit, virtual/physical cards, and managing their lifecycle (freeze, report lost/stolen, activate, replace).
Package card is the Cards bounded context: issuing individual/business, debit/credit, virtual/physical cards, and managing their lifecycle (freeze, report lost/stolen, activate, replace).
chargeback
Package chargeback is the Chargebacks bounded context: disputing card transactions on behalf of a customer.
Package chargeback is the Chargebacks bounded context: disputing card transactions on behalf of a customer.
checkdeposit
Package checkdeposit is the Check Deposits bounded context: mobile remote check deposit, including front/back image upload.
Package checkdeposit is the Check Deposits bounded context: mobile remote check deposit, including front/back image upload.
checkpayment
Package checkpayment is the Check Payments bounded context: print-and-mail outgoing check payments, cancellation, returns, and retrieving the rendered check image.
Package checkpayment is the Check Payments bounded context: print-and-mail outgoing check payments, cancellation, returns, and retrieving the rendered check image.
counterparty
Package counterparty is the Counterparties bounded context: saved external bank accounts used as the destination for ACH payments.
Package counterparty is the Counterparties bounded context: saved external bank accounts used as the destination for ACH payments.
customer
Package customer is the Customers bounded context: reading, updating, archiving customers, and managing authorized users on individual customers.
Package customer is the Customers bounded context: reading, updating, archiving customers, and managing authorized users on individual customers.
event
Package event is the Events bounded context: querying the last 90 days of account/webhook events and requesting redelivery ("fire") for replay.
Package event is the Events bounded context: querying the last 90 days of account/webhook events and requesting redelivery ("fire") for replay.
institution
Package institution is the Institutions bounded context: looking up receiving-bank details by ACH/wire routing number.
Package institution is the Institutions bounded context: looking up receiving-bank details by ACH/wire routing number.
payment
Package payment is the Payments bounded context: originating ACH (same- day and standard), Wire, Book, and Bulk payments, and managing received ACH payments.
Package payment is the Payments bounded context: originating ACH (same- day and standard), Wire, Book, and Bulk payments, and managing received ACH payments.
recurringpayment
Package recurringpayment is the Recurring Payments bounded context: scheduled recurring ACH/book payments and recurring credit-account repayments on a configurable interval.
Package recurringpayment is the Recurring Payments bounded context: scheduled recurring ACH/book payments and recurring credit-account repayments on a configurable interval.
repayment
Package repayment is the Repayments bounded context: one-off book/ACH repayments toward a credit account, including the capital-partner variants used in partner-funded credit programs.
Package repayment is the Repayments bounded context: one-off book/ACH repayments toward a credit account, including the capital-partner variants used in partner-funded credit programs.
sandbox
Package sandbox is the Sandbox bounded context: simulating inbound events (received ACH/wire, card transactions, chargebacks, check deposit clearing, application document review) against Unit's sandbox environment.
Package sandbox is the Sandbox bounded context: simulating inbound events (received ACH/wire, card transactions, chargebacks, check deposit clearing, application document review) against Unit's sandbox environment.
statement
Package statement is the Statements bounded context: listing account statements and retrieving them as HTML or PDF (including bank-branded PDF).
Package statement is the Statements bounded context: listing account statements and retrieving them as HTML or PDF (including bank-branded PDF).
stoppayment
Package stoppayment is the Stop Payments bounded context: placing ACH and check stop-payment orders on an account.
Package stoppayment is the Stop Payments bounded context: placing ACH and check stop-payment orders on an account.
token
Package token is the Tokens bounded context: issuing scoped bearer tokens for customers, cardholders, and org-level service accounts, and verifying two-factor codes to elevate a customer token's scope.
Package token is the Tokens bounded context: issuing scoped bearer tokens for customers, cardholders, and org-level service accounts, and verifying two-factor codes to elevate a customer token's scope.
transaction
Package transaction is the Transactions bounded context: reading the full transaction ledger for an account (purchases, ACH, wire, book, fees, interest, dishonored/return transactions, and more) and tagging them.
Package transaction is the Transactions bounded context: reading the full transaction ledger for an account (purchases, ACH, wire, book, fees, interest, dishonored/return transactions, and more) and tagging them.
webhook
Package webhook is the Webhooks bounded context: managing subscription lifecycle for Unit's event webhooks, and verifying inbound webhook signatures.
Package webhook is the Webhooks bounded context: managing subscription lifecycle for Unit's event webhooks, and verifying inbound webhook signatures.
internal
jsonapi
Package jsonapi implements just enough of the JSON:API specification (https://jsonapi.org) to speak Unit's wire protocol: resource objects, to-one/to-many relationships, top-level documents, included resources, and cursor-based pagination links.
Package jsonapi implements just enough of the JSON:API specification (https://jsonapi.org) to speak Unit's wire protocol: resource objects, to-one/to-many relationships, top-level documents, included resources, and cursor-based pagination links.
transport
Package transport is the infrastructure layer shared by every domain package: it owns the HTTP round trip, authentication, retry/backoff, idempotency key injection, and JSON:API (de)serialization.
Package transport is the infrastructure layer shared by every domain package: it owns the HTTP round trip, authentication, retry/backoff, idempotency key injection, and JSON:API (de)serialization.
Package shared contains the shared-kernel value objects used across every bounded context in unit-go: money, addresses, names, phone numbers, tags, and JSON:API relationship pointers.
Package shared contains the shared-kernel value objects used across every bounded context in unit-go: money, addresses, names, phone numbers, tags, and JSON:API relationship pointers.
Package telemetry defines the instrumentation hooks unit-go emits around every outbound request, mirroring the [:unit, :request, :start/:stop/ :exception] and retry events from the Elixir `unit` package.
Package telemetry defines the instrumentation hooks unit-go emits around every outbound request, mirroring the [:unit, :request, :start/:stop/ :exception] and retry events from the Elixir `unit` package.

Jump to

Keyboard shortcuts

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