Getting started
Step 1 – Install Go
Install Go before you use the SDK. The SDK declares Go 1.26 ingo.mod. Its public API 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 add the SDK 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 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 each API service.
- Built-in data models (like
CreateOrganizationInput). - Auth via Access Manager (production) or Anonymous (local development).
- A typed configuration system that fails at construction time.
Step 5 – Run the project
Run the following command:SDK architecture
Layered design
Services
Midaz serves two ledger API versions:/v1, which is deprecated, and /v2. The SDK groups the ledger services by the version that serves them. Build against c.V2. A resource that one version does not serve is a compile error, not a 404.
Transactions has a different contract on each version. On /v1, you create a transaction through one of four creation endpoints with a nested send body. On /v2, c.V2.Transactions creates transactions with a flat body through CreateDirect, CreateHold, CreateBlock, and CreateUnblock. It returns models.TransactionV2.
A
201 response means that Midaz accepted the transaction, not that the balances are settled. To wait for the balance effect, use transaction.WaitForSettlement from the pkg/transaction package.Models
Each model type represents a business concept. You use them in each service call. The most common model types are re-exported on themidaz package. midaz.Account and models.Account are the same type, so most code needs only one import.
Common model types
Utility packages
Thepkg folder of the SDK holds utility packages. Core packages serve concerns that apply to the whole SDK. Helper packages give domain-specific or low-level utilities.
Core packages
Helper packages
Authentication
The SDK requires exactly one authentication source at construction time. If you call
midaz.New(...) with neither, it returns a typed configuration error.
You have two choices:
midaz.WithAccessManager(...): OAuth through the Lerian Access Manager. Use it for any non-local stack.midaz.WithAnonymous(): no authentication. Use it only for a local Midaz stack with auth disabled.
Production: Access Manager
Put your Access Manager credentials inmidaz.WithAccessManager. The SDK requests a token from your Access Manager, attaches it to each API call, and refreshes it when it expires.
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 with 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. Put
config.FromEnvironment() in the option chain. The SDK does not read environment variables during construction without it.Tenant scope
Tenant scope comes from the Access Manager / JWT claims used to obtain the token. The SDK has no tenant configuration and does not send a tenant header. 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
Most list endpoints come in three methods. Pick the one that matches your use case.
Typed list options
Each list method takes a typed opts struct. The struct embeds one of two base structs, based on how the endpoint paginates:
Some endpoints also expose a typed
Filters sub-struct. If you set a field of the wrong shape (for example, Page on a cursor endpoint), the code does not compile.
Iterate every item with All
The simplest shape is a range loop over each item across each page. The SDK fetches the pages internally.
Iterate page envelopes with Pages
When you need page-level metadata (for checkpointing, batching, or stopping mid-page), iterate over Pages. Each entry is a *models.ListResponse[T] with its Pagination block.
NextCursor handling and the page-vs-cursor decision table.
Error handling
The SDK service layer returns errors as
*pkg/errors.Error with structured fields:
You can branch with typed predicates, read fields with
errors.As, or use the Retryable() method to drive retry policy.
Branch with typed predicates
The SDK has a set ofIs* predicates, so you can match errors without reading internals:
Drive retry decisions with Retryable()
The Error.Retryable() method derives from Category. Use it instead of your own classification.
Wrap raw transport errors
If you call lower-level HTTP code outside the SDK and want the same structured error shape, useClassifyTransportError:
Local validation: FieldErrors
Local input validation returns*pkg/validation.FieldErrors, a collection of per-field errors that the SDK finds before any HTTP call. Use errors.As to read them.
Retries
The default policy retries 3 times with exponential backoff and 25% jitter. It retries transport errors and the statuses
408, 425, 429, 500, 502, 503, and 504. The SDK retries POST, PUT, PATCH, and DELETE only when the request has an X-Idempotency header.
midaz.WithCustomRetryPolicy for your own retry predicate. To turn retries off, use midaz.WithoutRetries().
Logging
*slog.Logger is the logger surface of the SDK. Wire it with midaz.WithLogger(...). The SDK is silent by default: it uses slog.DiscardHandler until you opt in.
You decide the handler, the level, and the destination.
slog.Handler.
Observability
One observability provider gives you spans, metrics, and OpenTelemetry-correlated logs through one wiring point. Pass a provider that you build, or pass options that the SDK assembles for you.
Wire a provider
Or pass options inline
traceparent propagation. Business log records carry safe IDs only: no payloads, names, addresses, or auth headers.
You can also wrap a block of business logic in a span with Client.Trace:
Idempotency
Auto-idempotency is on by default. The SDK sends an
X-Idempotency: <uuid> header on each unsafe HTTP request (POST, PUT, PATCH, DELETE). A retry after a transient failure then does not create a resource twice.
You can override the generated key per call when you need a stable key of your own. This is typical for saga steps, outbox rows, or UI submissions.
Set a stable key per request
Suppress idempotency for one call
For rare administrative calls, suppress the header per request:Disable globally
To turn auto-idempotency off everywhere, turn it off at the client level:MIDAZ_IDEMPOTENCY=false when you use config.FromEnvironment().
Environment variables
The SDK reads these variables only when
config.FromEnvironment() is in your config option chain.
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.
Explore the APIs
For more information about the APIs, refer to the following links:

