Getting started
Step 1 – Install Go
Before using the SDK, you must install Go on your machine. v4 declares Go 1.26 ingo.mod. The public API also uses iter.Seq2 and log/slog.
1
Go to the official Go website.
2
Download the installer for your OS (Windows, macOS, or Linux).
Step 2 – Create or use an existing Go project
Create a Go project: To create a Go project, use the following command:go.mod file in the root. If not, run the following command to create one:
Step 3 – Add the Midaz SDK
Inside your project directory, run the following command to pull the v4 SDK and add it to yourgo.mod and go.sum files:
Step 4 – Import the SDK
Create or open amain.go file and add the following content. The example below builds a client against your local Midaz stack with anonymous authentication, lists organizations, then creates a new one.
The example below targets a local Midaz stack with auth disabled. If you don’t have one running yet, see Getting started with Midaz to spin one up before running the snippet.
- The Midaz client for calling every API service.
- Built-in data models (like
CreateOrganizationInput). - Auth via Access Manager (production) or Anonymous (local development).
- A typed configuration system that fails fast at construction time.
Step 5 – Run the project
Run the following command:SDK architecture
The Midaz SDK for Go is built around clarity and predictability. Every service is reachable directly on the client. Every list method follows the same trio shape. Every error is structured. Every option fails fast at construction time.
Layered design
Services are reached directly on the client —
c.Accounts, c.Transactions, c.Organizations. You may still see an embedded Entity field in autocomplete, but new code should use the direct service fields shown in this guide.Services
TheServices layer is your access point to every Midaz domain. Each service handles one resource family and ships every method as part of its single interface — no UseAllAPIs() toggle, no service registration step. Every service is ready to use the moment midaz.New() returns.
Available services
Models
Models reflect how Midaz thinks about finance, with each type tied closely to a real-world business concept. You’ll use them across every service call — from onboarding accounts to recording multi-leg transactions. In v4, the most common model types are re-exported on themidaz package itself. That means midaz.Account and models.Account are the same type, and most code only needs one import.
Common model types
Utility packages
Inside thepkg folder of the SDK, you’ll find utility packages for common dev challenges — config handling, retry policies, and security primitives. They split into two groups. Core packages power cross-cutting SDK concerns. Helper packages provide domain-specific or low-level utilities.
Core packages
Helper packages
The v2
pkg/access-manager package has moved to pkg/auth (so the directory matches the package name). The v2 pkg/pagination package was removed — its surface lives in models and on each service today.Authentication
In v4, the SDK requires exactly one authentication source at construction time. Calling
midaz.New(...) with neither returns a typed configuration error — no more silent 401 cascades on the first API call.
You have two choices:
midaz.WithAccessManager(...)— production-shape OAuth via the Lerian Access Manager. Recommended for any non-local stack.midaz.WithAnonymous()— opt out of authentication entirely. Suitable only for a local Midaz stack with auth disabled.
Production: Access Manager
Plug your Access Manager credentials intomidaz.WithAccessManager. The SDK eagerly fetches an initial token at construction time, so misconfigurations surface as configuration errors instead of cascading 401s.
Local development: Anonymous
For a local Midaz stack with auth disabled, opt out explicitly:Configure via environment variables
You can also point the SDK at your Access Manager via environment variables. Export them in your shell or your process manager:config.FromEnvironment() reads the process environment, not a .env file. If you keep variables in a .env file during development, load them with a library like godotenv before calling config.NewConfig(config.FromEnvironment()).Environment loading is explicit in v4 —
config.FromEnvironment() must be in the option chain. The SDK no longer reads env vars implicitly during construction.Multi-tenancy
Tenant scope comes from the Access Manager / JWT claims used to obtain the token. The SDK applies tenant identity automatically from those claims — no extra configuration on the client side. To run calls under a different tenant scope, use a separate set of Access Manager credentials — or build a second client with its own token context.
Listing and iteration
Every list endpoint in v4 ships in three flavors. Pick the one that matches your use case — they’re consistent across every service.
Typed list options
Each list method takes a typed opts struct that embeds one of two base structs depending on how the endpoint paginates:
Each endpoint also exposes a typed
Filters sub-struct with only the fields that endpoint actually honors. Setting a field on the wrong shape — for example, Page on a cursor endpoint — fails at compile time, not silently at runtime.
Iterate every item with ListAll
The most idiomatic shape: a range loop over every item across every page. The SDK advances cursors and fetches pages internally.
Iterate page envelopes with ListPages
When you need page-level metadata — for checkpointing, batching, or stopping mid-page — iterate over ListXxxPages instead. Every entry is a *ListResponse[T] with the full Pagination block attached.
HasMore() semantics, NextCursor handling, and the page-vs-cursor decision table.
Error handling
Most errors returned by the SDK service layer are
*pkg/errors.Error with structured fields:
You can branch with typed predicates, walk fields with
errors.As, or use the canonical Retryable() method to drive retry policy.
Branch with typed predicates
The SDK ships with a full set ofIs* predicates so you can match errors without poking at internals:
Drive retry decisions with Retryable()
The Error.Retryable() method is the canonical retry-policy source. Use it instead of building your own classification.
Wrap raw transport errors
If you’re calling lower-level HTTP code outside the SDK and want the same structured error shape, useClassifyTransportError:
Local validation: FieldErrors
Local input validation surfaces*pkg/validation.FieldErrors — a structured collection of per-field complaints from the SDK before any HTTP call. Use errors.As to inspect them when validating user input or builders.
Logging
In v4,
*slog.Logger is the canonical logger surface. Wire it via midaz.WithLogger(...). The SDK is silent by default — it uses slog.DiscardHandler until you opt in.
That means no surprise log lines in your stdout, and no fighting with the SDK over log format. You decide the handler, the level, and the destination.
slog.Handler adapters — the SDK doesn’t care which backend produces the records, only that it speaks slog.
Observability
OpenTelemetry is first-class in v4. One observability provider gives you spans, metrics, and OTel-correlated logs through a single wiring point. Configure observability either by passing a fully-built provider, or by passing options that the SDK assembles for you.
Wire a provider
Or pass options inline
traceparent propagation. Business log records carry safe IDs only — never payloads, names, addresses, or auth headers.
You can also wrap a block of business logic in a span via Client.Trace:
Idempotency
Auto-idempotency is on by default in v4. The SDK emits an
X-Idempotency: <uuid> header on every unsafe HTTP request (POST, PUT, PATCH, DELETE). Retries on transient failures then do not double-create resources.
You can override the auto-generated key per-call when you need a stable, caller-supplied key — typical for saga steps, outbox rows, or UI-driven submissions.
Set a stable key per request
Suppress idempotency for one call
For rare fire-and-forget administrative endpoints, suppress the header per-request:Disable globally
If you don’t want auto-idempotency anywhere, turn it off at the client level:MIDAZ_IDEMPOTENCY=false environment variable when using config.FromEnvironment().
Environment variables
You can configure the SDK with environment variables instead of hardcoded values. Environment loading is explicit in v4 — pass
config.FromEnvironment() in your config option chain to opt in.
For the full option matrix across
midaz, pkg/config, and pkg/sdkctx, see the Configuration guide in the SDK repo.
Example projects
concurrency, configuration, context, tracing, tracing-server, pkg-validation-demo, mass-demo-generator, and workflow-with-entities. They cover advanced patterns (bounded parallelism, OTel context propagation across processes, mass data generation) for when you’ve outgrown the focused set.
Migrating from v2
v4 is a clean-cut major version with no deprecation window. There is no transitional release, no
// Deprecated: shim, no backward-compatible alias of the old surface. Swap your import from /v2 to /v4 and walk the breaking changes below.
The biggest moves to plan for:
- Module path and package name:
github.com/LerianStudio/midaz-sdk-golang/v4(was/v2), packagemidaz(wasclient). - Authentication:
WithAuthTokenis gone. UseWithAccessManagerfor production orWithAnonymousfor local stacks. One auth source is required at construction time. - Service access:
c.Accounts.X(wasc.Entity.Accounts.X). Thec.Entityfield still exists for compatibility, but every example uses the short form. - Pagination:
models.ListOptionsand its 30 fluent setters are gone. Use the typed per-endpoint opts (models.AccountsListOpts,models.TransactionsListOpts, …) and the newListAll/ListPagesiterators. - Errors:
*MidazErroris gone. Service-layer errors now use*pkg/errors.ErrorwithRetryable()as the official retry source. Local validation may surface*pkg/validation.FieldErrors. - Tenant identity:
WithTenantID, theMIDAZ_TENANT_IDenv var, and theX-Tenant-IDheader are gone. Tenant scope flows through Access Manager / JWT claims. - Logging:
*slog.Loggerreplaces the bespokeobservability.Loggerinterface as the canonical surface. The SDK is silent by default.
Explore the APIs
For more information about the APIs, refer to the following links:

