> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK do Midaz para Go

> Crie aplicações Go sobre o Midaz com o SDK oficial para Go: paginação tipada, erros estruturados, novas tentativas e observabilidade OpenTelemetry.

O **SDK do Midaz para Go** é o cliente Go para as APIs do ledger e do Tracer do Midaz. Ele oferece acesso tipado aos serviços que a tabela Services lista (Organizations, Ledgers, Accounts, Transactions e mais) com uma única superfície para autenticação, paginação, erros, novas tentativas, logging e observabilidade.

## Primeiros passos

***

### Passo 1 – Instalar o Go

Instale o Go antes de usar o SDK. O SDK declara **Go 1.26** no `go.mod`. A API pública dele usa `iter.Seq2` e `log/slog`.

**Step 1**

Acesse o [site oficial do Go](https://golang.org/dl/).

**Step 2**

Baixe o instalador para o seu sistema operacional (Windows, macOS ou Linux).

**Step 3**

[**Siga as instruções de instalação.**](https://go.dev/doc/install)

### Passo 2 – Criar ou usar um projeto Go existente

**Criar um projeto Go:**

Para criar um projeto Go, use o comando a seguir:

```bash Bash theme={null}
mkdir my-midaz-app
cd my-midaz-app
go mod init my-midaz-app
```

**Usar um projeto Go existente:**

Se você já está trabalhando em um projeto existente, confirme que há um arquivo `go.mod` na raiz. Caso não haja, execute o comando a seguir para criar um:

```bash Bash theme={null}
go mod init your-module-name
```

### Passo 3 – Adicionar o SDK do Midaz

Dentro do diretório do seu projeto, execute o comando a seguir para adicionar o SDK aos arquivos `go.mod` e `go.sum`:

> [!WARNING]
>
> **O caminho do módulo exige o sufixo `/v6`.** Se você omitir esse sufixo, o Go resolve uma versão v1 antiga. Importe `github.com/LerianStudio/midaz-sdk-golang/v6`.

```bash Bash theme={null}
go get github.com/LerianStudio/midaz-sdk-golang/v6
```

> [!TIP]
>
> No VS Code ou no GoLand, sua IDE pode executar `go get` automaticamente quando você importa um pacote novo.

### Passo 4 – Importar o SDK

Crie ou abra um arquivo `main.go` e adicione o conteúdo a seguir. O exemplo cria um cliente para a sua stack local do Midaz com autenticação anônima, lista organizações e, em seguida, cria uma nova.

> [!NOTE]
>
> O exemplo abaixo é para uma stack local do Midaz com autenticação desabilitada. Se você ainda não tem uma rodando, veja [Primeiros passos com o Midaz](https://docs.lerian.studio/pt/start-here/getting-started.md) para subir uma antes de executar o snippet.

```go Go expandable theme={null}
package main

import (
	"context"
	"fmt"
	"log"

	midaz "github.com/LerianStudio/midaz-sdk-golang/v6"
	"github.com/LerianStudio/midaz-sdk-golang/v6/models"
)

func main() {
	// Build a client. The SDK requires exactly one auth source: use
	// midaz.WithAnonymous() for a local stack, or midaz.WithAccessManager(...)
	// for a development or production environment.
	c, err := midaz.New(
		midaz.WithEnvironment(midaz.EnvironmentLocal),
		midaz.WithAnonymous(),
	)
	if err != nil {
		log.Fatalf("midaz.New: %v", err)
	}
	defer c.Shutdown(context.Background())

	ctx := context.Background()

	// List the first 5 organizations using a typed list-opts struct.
	page, err := c.V2.Organizations.List(ctx, models.OrganizationsListOpts{
		PageListOpts: models.PageListOpts{Limit: 5},
	})
	if err != nil {
		log.Fatalf("list organizations: %v", err)
	}

	for _, org := range page.Items {
		fmt.Printf("- %s (%s)\n", org.LegalName, org.ID)
	}

	// Create a new organization. midaz.CreateOrganizationInput is the same
	// type as models.CreateOrganizationInput, re-exported on the midaz package.
	dba := "Example Inc."
	org, err := c.V2.Organizations.Create(ctx, &midaz.CreateOrganizationInput{
		LegalName:       "Example Corporation",
		LegalDocument:   "123456789",
		DoingBusinessAs: &dba, // optional fields are *string
		Address: midaz.Address{
			Line1:   "123 Main St",
			City:    "New York",
			State:   "NY",
			ZipCode: "10001",
			Country: "US",
		},
	})
	if err != nil {
		log.Fatalf("create organization: %v", err)
	}

	fmt.Printf("Organization created: %s\n", org.ID)
}
```

Isso oferece acesso a:

* O cliente do Midaz para chamar cada serviço da API.
* Modelos de dados prontos (como `CreateOrganizationInput`).
* Autenticação via **Access Manager** (produção) ou **Anônimo** (desenvolvimento local).
* Um sistema de configuração tipado que falha no momento da construção.

> [!TIP]
>
> Para a configuração completa, veja a seção [Autenticação](#authentication).

### Passo 5 – Executar o projeto

Execute o comando a seguir:

```bash Bash theme={null}
go run main.go
```

## Arquitetura do SDK

***

#### Design em camadas

| Camada | O que ela trata |
| :- | :- |
| **Client** | O ponto de entrada principal. `midaz.New(...)` conecta autenticação, novas tentativas e observabilidade. |
| **Services** | Os serviços do Midaz que o SDK encapsula, agrupados pela versão da API que os atende. |
| **Models** | As estruturas de dados do domínio do Midaz. As mais comuns são reexportadas no pacote `midaz`. |
| **Utility packages** | Helpers para configuração, erros, observabilidade, novas tentativas, idempotência e mais. |

### Services

O Midaz atende duas versões da API do ledger: `/v1`, que está descontinuada, e `/v2`. O SDK agrupa os serviços do ledger pela versão que os atende. **Desenvolva sobre `c.V2`.** Um recurso que uma versão não atende gera erro de compilação, não um 404.

```go Go theme={null}
orgs, err := c.V2.Organizations.List(ctx, opts)
account, err := c.V2.Accounts.Get(ctx, orgID, ledgerID, accountID)
tx, err := c.V2.Transactions.CreateDirect(ctx, orgID, ledgerID, input)

// /v1 only:
rate, err := c.V1.AssetRates.GetAssetRate(ctx, orgID, ledgerID, externalID)
```

| Grupo | Serviços |
| :- | :- |
| `c.V2` e `c.V1` | `Organizations`, `Ledgers`, `Accounts`, `AccountTypes`, `Assets`, `Balances`, `Operations`, `Portfolios`, `Segments`, `OperationRoutes`, `TransactionRoutes`, `Transactions`, `MetadataIndexes` |
| Apenas `c.V2` | `Holders`, `Instruments`, `Encryption`, `Composition`, `ProtectionAudit`, `BillingPackages`, `FeePackages`, `FeeEstimates`, `BillingCalculations` |
| Apenas `c.V1` | `AssetRates` |
| Tracer, no cliente | `c.Rules`, `c.Limits`, `c.Validations`, `c.AuditEvents` |

`Transactions` tem um contrato diferente em cada versão. Na `/v1`, você cria uma transação por um de quatro endpoints de criação com um body `send` aninhado. Na `/v2`, `c.V2.Transactions` cria transações com um body plano por meio de `CreateDirect`, `CreateHold`, `CreateBlock` e `CreateUnblock`. Ele retorna `models.TransactionV2`.

Para postar várias transações `direct` e `hold` como um lote ordenado, use `c.V2.Transactions.CreateBatch`. O Midaz aplica todos os itens, na ordem, ou nenhum. Cada item é um `models.TransactionBatchItemV2` com uma `Action` (`direct` ou `hold`) e uma `Order` (começa em um e é consecutiva). A chamada retorna as transações nessa ordem. O lote tem uma única chave de idempotência, que você define com `sdkctx.WithIdempotencyKey`. Um item que define a própria `IdempotencyKey` é recusado.

> [!NOTE]
>
> Uma resposta `201` significa que o Midaz aplicou a transação aos saldos.

### Ler a versão do servidor

`c.ServerVersion` lê a versão do ledger Midaz com o qual o cliente se comunica. Ele retorna um erro quando o ledger não responde com uma versão.

`midaz.SupportsRulesOnly` informa se o Tracer dessa versão aceita a validação somente por regras. `c.Validations.EvaluateRulesOnly` julga uma transação apenas pelas regras: não verifica nenhum limite de gasto e não conta nada contra um limite.

```go Go theme={null}
v, err := c.ServerVersion(ctx)
if err != nil {
    return fmt.Errorf("read server version: %w", err)
}

if midaz.SupportsRulesOnly(v) {
    verdict, err := c.Validations.EvaluateRulesOnly(ctx, input) // input is a *models.ValidateTransactionInput
    if err != nil {
        return err
    }
    _ = verdict
}
```

### Models

Cada tipo de modelo representa um conceito de negócio. Você os usa em cada chamada de serviço.

Os tipos de modelo mais comuns são reexportados no pacote `midaz`. `midaz.Account` e `models.Account` são o mesmo tipo, então a maior parte do código precisa de apenas um import.

`midaz.Account` traz `ClosedAt`, o momento em que o Midaz encerrou a conta. Ele é `nil` enquanto a conta está aberta. Encerrar uma conta não altera `Status`.

#### Tipos de modelo comuns

| Modelo | O que ele representa |
| :- | :- |
| `midaz.Organization` | Uma entidade de negócio que é dona de ledgers e contas. |
| `midaz.Ledger` | Uma coleção de contas e transações. |
| `midaz.Asset` | Uma unidade de valor (moeda, token etc.) que pode ser armazenada ou movimentada. |
| `midaz.Account` | Uma conta para rastrear ativos e saldos. |
| `midaz.Portfolio` | Uma coleção de contas para agrupamento e gestão. |
| `midaz.Segment` | Uma unidade de categorização para organização granular. |
| `midaz.Transaction` | Um evento financeiro composto por múltiplas operações. |
| `midaz.Operation` | Um lançamento individual de débito ou crédito dentro de uma transação. |
| `midaz.Balance` | O estado atual das posições de uma conta. |

> [!TIP]
>
> Para um tipo que não é reexportado, como `models.TransactionV2`, importe `github.com/LerianStudio/midaz-sdk-golang/v6/models` diretamente. Os aliases de `midaz` preservam a identidade do tipo, então os dois caminhos de import funcionam juntos.

### Utility packages

A pasta `pkg` do SDK guarda pacotes utilitários. Os pacotes **Core** atendem preocupações que valem para todo o SDK. Os pacotes **Helper** oferecem utilitários específicos de domínio ou de baixo nível.

#### Core packages

| Pacote | O que ele resolve |
| :- | :- |
| `auth` | OAuth do Access Manager e ciclo de vida do token. |
| `config` | Tratamento de configuração, carregamento por ambiente e URLs de serviço personalizadas. |
| `concurrent` | Ferramentas para lotes, rate limiting e worker pools. |
| `errors` | Tipos de erro estruturados, classificadores e o predicado `Retryable()`. |
| `observability` | Tracing, métricas e logs por meio de um único provedor OpenTelemetry. |
| `retry` | Opções de política de novas tentativas com backoff exponencial e jitter. |
| `sdkctx` | Flags de contexto por requisição, como chaves de idempotência. |
| `validation` | Validação de entrada com mensagens de erro estruturadas. |

#### Helper packages

| Pacote | O que ele resolve |
| :- | :- |
| `accounts` | Helpers específicos de conta e funções de conveniência. |
| `conversion` | Helpers de conversão de tipo entre modelos e formatos externos. |
| `data` | Utilitários de dados e helpers faker para testes e demonstrações. |
| `format` | Utilitários para formatar dados no padrão Midaz (datas, horários etc.). |
| `generator` | Geração de dados de demonstração e em massa para cenários ponta a ponta. |
| `integrity` | Utilitários de checksum e verificação de integridade. |
| `performance` | Helpers para ajustar operações em lote e tarefas de alto throughput. |
| `security` | Utilitários de segurança, incluindo proteção contra SSRF e validação de TLS. |
| `stats` | Estatísticas de processamento e agregação de métricas. |
| `transaction` | Helpers de transação, como a espera de liquidação. |
| `utils` | Helpers de uso geral usados em todo o SDK. |
| `version` | Metadados de versão e identificação do SDK. |

## Autenticação

***

O SDK exige exatamente uma fonte de autenticação no momento da construção. Se você chamar `midaz.New(...)` sem nenhuma das duas, ele retorna um erro de configuração tipado.

Você tem duas opções:

* **`midaz.WithAccessManager(...)`**: OAuth pelo Lerian Access Manager. Use em qualquer stack que não seja local.
* **`midaz.WithAnonymous()`**: sem autenticação. Use apenas em uma stack local do Midaz com autenticação desabilitada.

Se você aplicar as duas opções, vale a última.

### Produção: Access Manager

Coloque suas credenciais do Access Manager em `midaz.WithAccessManager`. O SDK solicita um token ao seu Access Manager, anexa esse token a cada chamada de API e o renova quando ele expira.

> [!WARNING]
>
> Substitua os valores no bloco `// Configure Access Manager` pelas suas próprias credenciais antes de executar.

```go Go expandable theme={null}
package main

import (
	"context"
	"log"
	"os"

	midaz "github.com/LerianStudio/midaz-sdk-golang/v6"
)

func main() {
	// Configure Access Manager. Load ClientID and ClientSecret from
	// environment variables; do not hardcode them.
	c, err := midaz.New(
		midaz.WithEnvironment(midaz.EnvironmentProduction),
		midaz.WithAccessManager(midaz.AccessManager{
			Address:      "https://auth.example.com",
			ClientID:     os.Getenv("MIDAZ_CLIENT_ID"),
			ClientSecret: os.Getenv("MIDAZ_CLIENT_SECRET"),
		}),
	)
	if err != nil {
		log.Fatalf("midaz.New: %v", err)
	}
	defer c.Shutdown(context.Background())

	// Use c.V2.Organizations, c.V2.Ledgers, c.V2.Accounts, ...
}
```

### Desenvolvimento local: Anônimo

Para uma stack local do Midaz com autenticação desabilitada, desative a autenticação explicitamente:

```go Go theme={null}
c, err := midaz.New(
    midaz.WithEnvironment(midaz.EnvironmentLocal),
    midaz.WithAnonymous(),
)
```

### Configurar via variáveis de ambiente

Você também pode apontar o SDK para o seu Access Manager com variáveis de ambiente. Exporte-as no seu shell ou no seu gerenciador de processos:

```bash Bash theme={null}
export PLUGIN_AUTH_ENABLED=true
export PLUGIN_AUTH_ADDRESS=https://your-auth-service.com
export MIDAZ_CLIENT_ID=your-client-id
export MIDAZ_CLIENT_SECRET=your-client-secret
```

> [!NOTE]
>
> `config.FromEnvironment()` lê o **ambiente de processo**, não um arquivo `.env`. Se você mantém variáveis em um arquivo `.env` durante o desenvolvimento, carregue-as com uma biblioteca como `godotenv` antes de chamar `config.NewConfig(config.FromEnvironment())`.

Depois, habilite o carregamento por ambiente no momento da configuração:

```go Go theme={null}
import "github.com/LerianStudio/midaz-sdk-golang/v6/pkg/config"

cfg, err := config.NewConfig(config.FromEnvironment())
if err != nil {
    log.Fatalf("config: %v", err)
}

c, err := midaz.New(midaz.WithConfig(cfg))
```

> [!NOTE]
>
> O carregamento por ambiente é **explícito**. Coloque `config.FromEnvironment()` na cadeia de opções. Sem ele, o SDK não lê variáveis de ambiente durante a construção.

> [!TIP]
>
> Para o passo a passo completo de autenticação, veja o [guia de autenticação](https://github.com/LerianStudio/midaz-sdk-golang/blob/main/docs/auth.md) no repositório do SDK.

## Escopo de tenant

***

**O escopo do tenant vem do Access Manager / das claims do JWT** usadas para obter o token. O SDK não tem configuração de tenant e não envia um header de tenant.

Para executar chamadas em um escopo de tenant diferente, use um conjunto separado de credenciais do Access Manager, ou construa um segundo cliente com seu próprio contexto de token.

## Listagem e iteração

***

A maioria dos endpoints de listagem vem em três métodos. Escolha o que corresponde ao seu caso de uso.

| Método | Retorna | Use quando |
| :- | :- | :- |
| `List` | `*models.ListResponse[T]` (uma página) | Você quer exatamente uma página e decide quando avançar. |
| `All` | `iter.Seq2[T, error]` | Você quer cada item. O SDK trata a paginação internamente. |
| `Pages` | `iter.Seq2[*models.ListResponse[T], error]` | Você precisa de metadados no nível de página para checkpointing ou processamento em lote. |

### Opções de listagem tipadas

Cada método de listagem recebe uma struct de opções tipada. A struct incorpora uma de duas structs base, de acordo com a forma como o endpoint pagina:

| Formato de paginação | Endpoints | Struct base |
| :- | :- | :- |
| **Por página** | Organizations, Ledgers, Assets, Portfolios, Segments, Accounts, AccountTypes, FeePackages, BillingPackages | `models.PageListOpts{Limit, Page, SortDirection, StartDate, EndDate}` |
| **Por cursor** | Transactions, Balances, Holders, Operations, OperationRoutes, TransactionRoutes, AssetRates | `models.CursorListOpts{Limit, Cursor, SortDirection, StartDate, EndDate}` |

Alguns endpoints também expõem uma sub-struct `Filters` tipada. Se você definir um campo do formato errado (por exemplo, `Page` em um endpoint por cursor), o código não compila.

> [!WARNING]
>
> A listagem de transações não filtra por `Status`, `AssetCode`, `Reference`, `SourceAccount`, `DestinationAccount` ou `Route`. Se você definir um desses filtros em `List`, o SDK recusa a chamada com um erro. `Count` aceita `Status` e `Route`.

### Iterar por cada item com `All`

O formato mais simples é um loop `range` sobre cada item em cada página. O SDK busca as páginas internamente.

```go Go theme={null}
opts := models.AccountsListOpts{
    PageListOpts: models.PageListOpts{Limit: 100},
    Filters: models.AccountsFilters{
        Status:    "ACTIVE",
        AssetCode: "USD",
    },
}

for account, err := range c.V2.Accounts.All(ctx, orgID, ledgerID, opts) {
    if err != nil {
        return fmt.Errorf("list accounts: %w", err)
    }
    process(account)
}
```

### Iterar envelopes de página com `Pages`

Quando você precisa de metadados no nível de página (para checkpointing, processamento em lote ou parar no meio de uma página), itere sobre `Pages`. Cada entrada é um `*models.ListResponse[T]` com o seu bloco `Pagination`.

```go Go theme={null}
opts := models.TransactionsListOpts{
    CursorListOpts: models.CursorListOpts{Limit: 50},
}

for page, err := range c.V2.Transactions.Pages(ctx, orgID, ledgerID, opts) {
    if err != nil {
        return fmt.Errorf("page iter: %w", err)
    }
    log.Printf("items=%d next_cursor=%q", len(page.Items), page.Pagination.NextCursor)

    for _, tx := range page.Items {
        process(tx)
    }

    if shouldStop(page) {
        break // The SDK stops paging.
    }
}
```

Veja o [guia de paginação](https://github.com/LerianStudio/midaz-sdk-golang/blob/main/docs/pagination.md) no repositório do SDK para o tratamento de `NextCursor` e a tabela de decisão entre página e cursor.

## Tratamento de erros

***

A camada de serviços do SDK retorna erros como `*pkg/errors.Error` com campos estruturados:

| Campo | O que ele carrega |
| :- | :- |
| `Category` | A classe do erro (validação, autenticação, rede, configuração e assim por diante). |
| `Code` | Um código de string estável para ramificação ou telemetria. |
| `Operation` | A operação do SDK que gerou o erro. |
| `Resource` | A família de recurso a que o erro se refere, quando relevante. |

Você pode ramificar com predicados tipados, ler campos com `errors.As` ou usar o método `Retryable()` para guiar a política de novas tentativas.

### Ramificar com predicados tipados

O SDK tem um conjunto de predicados `Is*`, para que você identifique erros sem ler detalhes internos:

```go Go expandable theme={null}
import (
    "errors"
    "fmt"

    sdkerrors "github.com/LerianStudio/midaz-sdk-golang/v6/pkg/errors"
)

acc, err := c.V2.Accounts.Get(ctx, orgID, ledgerID, accountID)
if err != nil {
    switch {
    case sdkerrors.IsNotFoundError(err):
        return fmt.Errorf("account not found: %w", err)
    case sdkerrors.IsAuthError(err):
        return fmt.Errorf("auth failure: %w", err)
    case sdkerrors.IsValidationError(err):
        return fmt.Errorf("invalid input: %w", err)
    case sdkerrors.IsInsufficientBalanceError(err):
        return fmt.Errorf("not enough balance: %w", err)
    case sdkerrors.IsTransactionReservationDenied(err):
        return fmt.Errorf("refused by Tracer: %w", err)
    case sdkerrors.IsConflictError(err):
        return fmt.Errorf("already exists: %w", err)
    case sdkerrors.IsRateLimitError(err):
        return fmt.Errorf("rate limited: %w", err)
    case sdkerrors.IsNetworkError(err):
        return fmt.Errorf("transient transport: %w", err)
    case sdkerrors.IsConfigurationError(err):
        return fmt.Errorf("setup mistake: %w", err)
    }

    // Read the structured fields when you need them.
    var sdkErr *sdkerrors.Error
    if errors.As(err, &sdkErr) {
        log.Printf("op=%s resource=%s code=%s retryable=%v",
            sdkErr.Operation, sdkErr.Resource, sdkErr.Code, sdkErr.Retryable())
    }
}
```

### Guiar decisões de novas tentativas com `Retryable()`

O método `Error.Retryable()` deriva de `Category`. Use-o em vez da sua própria classificação.

```go Go theme={null}
var sdkErr *sdkerrors.Error
if errors.As(err, &sdkErr) && sdkErr.Retryable() {
    // Apply your retry logic: backoff, jitter, max attempts, etc.
}
```

### Envolver erros brutos de transporte

Se você chama código HTTP de nível mais baixo fora do SDK e quer o mesmo formato de erro estruturado, use `ClassifyTransportError`:

```go Go theme={null}
import sdkerrors "github.com/LerianStudio/midaz-sdk-golang/v6/pkg/errors"

resp, err := httpClient.Do(req)
if err != nil {
    return sdkerrors.ClassifyTransportError("PaymentService.Charge", err)
}
```

### Validação local: FieldErrors

A validação local de entrada retorna `*pkg/validation.FieldErrors`, uma coleção de erros por campo que o SDK encontra antes de qualquer chamada HTTP. Use `errors.As` para lê-los.

```go Go theme={null}
import (
    "errors"
    "fmt"

    "github.com/LerianStudio/midaz-sdk-golang/v6/pkg/validation"
)

var fieldErrs *validation.FieldErrors
if errors.As(err, &fieldErrs) {
    for _, fe := range fieldErrs.Errs() {
        fmt.Printf("- %s: %s\n", fe.Field, fe.Message)
    }
}
```

> [!TIP]
>
> Para o mapa completo de categorias, cada código e os limites de novas tentativas, veja o [guia de tratamento de erros](https://github.com/LerianStudio/midaz-sdk-golang/blob/main/docs/errors.md) no repositório do SDK.

## Novas tentativas

***

A política padrão faz 3 novas tentativas com backoff exponencial e 25% de jitter. Ela tenta de novo em erros de transporte e nos status `408`, `425`, `429`, `500`, `502`, `503` e `504`. O SDK tenta de novo um `POST`, `PUT`, `PATCH` ou `DELETE` quando a requisição tem um header `X-Idempotency`, ou quando é a criação de uma transação, de um titular ou de um instrumento, que o Midaz responde com o primeiro resultado quando a mesma requisição chega de novo. Ele envia uma única vez qualquer outra escrita.

Depois que uma escrita falha, o SDK para de tentar de novo quando a janela de idempotência passou desde o início da chamada. A janela é o valor de `X-TTL` da requisição, ou 300 segundos quando o header não existe. Um `409` com o código `0084` sob uma chave que você definiu volta como erro. O SDK só tenta de novo um `0084` sob a própria chave aleatória ou em uma criação sem chave.

```go Go theme={null}
import (
    "time"

    "github.com/LerianStudio/midaz-sdk-golang/v6/pkg/retry"
)

c, err := midaz.New(
    midaz.WithEnvironment(midaz.EnvironmentLocal),
    midaz.WithAnonymous(),
    midaz.WithRetryOptions(
        retry.WithMaxRetries(5),
        retry.WithInitialDelay(200*time.Millisecond),
    ),
)
```

Use `midaz.WithCustomRetryPolicy` para o seu próprio predicado de novas tentativas. Para desligar as novas tentativas, use `midaz.WithoutRetries()`.

## Logging

***

**`*slog.Logger` é a superfície de logger do SDK.** Conecte-o com `midaz.WithLogger(...)`. O SDK é **silencioso por padrão**: ele usa `slog.DiscardHandler` até você habilitar.

Você decide o handler, o nível e o destino.

```go Go expandable theme={null}
package main

import (
    "context"
    "log"
    "log/slog"
    "os"

    midaz "github.com/LerianStudio/midaz-sdk-golang/v6"
)

func main() {
    logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelInfo,
    }))

    c, err := midaz.New(
        midaz.WithEnvironment(midaz.EnvironmentLocal),
        midaz.WithAnonymous(),
        midaz.WithLogger(logger),
    )
    if err != nil {
        log.Fatalf("midaz.New: %v", err)
    }
    defer c.Shutdown(context.Background())

    // SDK log lines now go to your handler.
}
```

charmbracelet/log, zap e zerolog se integram por meio de `slog.Handler`.

> [!TIP]
>
> O [guia de logging](https://github.com/LerianStudio/midaz-sdk-golang/blob/main/docs/logging.md) tem receitas de adaptadores para bibliotecas de logging comuns.

## Observabilidade

***

Um provedor de observabilidade oferece spans, métricas e logs correlacionados ao OpenTelemetry.

Passe um provedor que você constrói, ou passe opções que o SDK monta para você.

### Conectar um provedor

```go Go expandable theme={null}
package main

import (
    "context"
    "log"

    midaz "github.com/LerianStudio/midaz-sdk-golang/v6"
    "github.com/LerianStudio/midaz-sdk-golang/v6/pkg/observability"
)

func main() {
    ctx := context.Background()

    provider, err := observability.New(ctx,
        observability.WithServiceName("payments-api"),
        observability.WithEnvironment("production"),
        observability.WithComponentEnabled(true, true, true), // tracing, metrics, logs
    )
    if err != nil {
        log.Fatalf("observability.New: %v", err)
    }
    defer provider.Shutdown(ctx)

    c, err := midaz.New(
        midaz.WithEnvironment(midaz.EnvironmentProduction),
        midaz.WithAccessManager(midaz.AccessManager{ /* ... */ }),
        midaz.WithObservabilityProvider(provider),
    )
    if err != nil {
        log.Fatalf("midaz.New: %v", err)
    }
    defer c.Shutdown(ctx)
}
```

### Ou passar opções inline

```go Go theme={null}
import "github.com/LerianStudio/midaz-sdk-golang/v6/pkg/observability"

c, err := midaz.New(
    midaz.WithEnvironment(midaz.EnvironmentProduction),
    midaz.WithAccessManager(am),
    midaz.WithObservabilityOptions(
        observability.WithServiceName("payments-api"),
        observability.WithComponentEnabled(true, true, true),
    ),
)
```

Sem `observability.WithCollectorEndpoint`, o SDK usa os provedores OpenTelemetry da sua aplicação e não os substitui. `c.Shutdown` fecha apenas um provedor que o SDK construiu. Se você passar o seu próprio provedor, encerre-o depois do último cliente que o usa.

Chamadas como `c.V2.Accounts.Get` não criam span nem enviam o header `traceparent` por conta própria. Para rastreá-las, envolva o transporte do cliente com o middleware de observabilidade:

```go Go theme={null}
c, err := midaz.New(
    midaz.WithEnvironment(midaz.EnvironmentProduction),
    midaz.WithAccessManager(am),
    midaz.WithObservabilityProvider(provider),
    midaz.WithHTTPTransport(observability.NewHTTPMiddleware(provider)),
)
```

`WithHTTPTransport` mantém o cliente HTTP do próprio SDK, com seu timeout, autenticação e novas tentativas, e envolve o transporte dele.

Você também pode envolver um bloco de lógica de negócio em um span com `Client.Trace`:

```go Go theme={null}
err = c.Trace("create-organization", func(ctx context.Context) error {
    _, err := c.V2.Organizations.Create(ctx, input)
    return err
})
```

> [!WARNING]
>
> `WithObservabilityOptions` e `WithObservabilityProvider` **substituem** o provedor instalado. Eles não mesclam. Para começar de uma base, coloque `observability.WithDevelopmentDefaults` ou `observability.WithProductionDefaults` primeiro na cadeia de opções.

> [!TIP]
>
> Veja o [exemplo `10-observability-otel`](https://github.com/LerianStudio/midaz-sdk-golang/tree/main/examples/10-observability-otel) no repositório do SDK para atributos de span, nomes de métricas e configuração de exporters.

## Idempotência

***

O SDK não gera uma chave `X-Idempotency` aleatória a menos que você ative essa opção. Sem uma chave sua, o Midaz trata uma criação de transação idêntica dentro da janela de idempotência (300 segundos por padrão) como uma repetição e retorna a primeira transação. Uma segunda transação intencional com a mesma requisição não é postada. Para ver como o Midaz trata a falta de chave, consulte [Novas tentativas e idempotência](https://docs.lerian.studio/pt/reference/retries-idempotency.md).

Defina uma chave distinta para cada transação que você pretende postar. Isso é comum em etapas de saga, linhas de outbox ou envios de UI.

### Definir uma chave estável por requisição

```go Go theme={null}
import "github.com/LerianStudio/midaz-sdk-golang/v6/pkg/sdkctx"

ctx := sdkctx.WithIdempotencyKey(context.Background(), "tx-2026-05-06-001")

tx, err := c.V2.Transactions.CreateDirect(ctx, orgID, ledgerID, input)
```

Uma chave que você define sempre prevalece sobre a opção do cliente e sobre `sdkctx.WithoutAutoIdempotency`.

> [!WARNING]
>
> O Midaz usa a chave nas criações de transação e nas criações de titular e instrumento. O Tracer não a usa. Se uma resposta se perde, a nova tentativa do SDK em qualquer outra escrita pode executá-la uma segunda vez, mesmo com chave. Desligue as novas tentativas do SDK para essas escritas, ou leia o recurso antes de tentar de novo.

### Ativar uma chave aleatória globalmente

Para enviar uma chave `X-Idempotency` aleatória em cada criação, atualização e exclusão, ative a opção no nível do cliente:

```go Go theme={null}
c, err := midaz.New(
    midaz.WithEnvironment(midaz.EnvironmentLocal),
    midaz.WithAnonymous(),
    midaz.WithIdempotency(true),
)
```

Você também pode definir `MIDAZ_IDEMPOTENCY=true` quando usa `config.FromEnvironment()`. Cada chamada passa a levar a própria chave, então duas transações intencionais com a mesma requisição são postadas separadamente. Uma nova tentativa de uma chamada reutiliza a chave dessa chamada.

### Interromper a chave aleatória em uma chamada

Quando o cliente está com a chave aleatória ligada, você pode interrompê-la em uma chamada:

```go Go theme={null}
ctx := sdkctx.WithoutAutoIdempotency(context.Background())
```

## Variáveis de ambiente

***

O SDK lê estas variáveis apenas quando `config.FromEnvironment()` está na sua cadeia de opções de configuração.

| Variável | Descrição |
| :- | :- |
| `MIDAZ_ENVIRONMENT` | Ambiente de destino (`local`, `development`, `production`). |
| `MIDAZ_BASE_URL` | URL base dos serviços do Midaz, usada quando as URLs específicas de serviço não estão definidas. Não adicione um sufixo `/v1` ou `/v2`. |
| `MIDAZ_LEDGER_URL` | URL da API do ledger. Ela atende os endpoints de onboarding e de transação. |
| `MIDAZ_TRACER_URL` | URL da API do Tracer. |
| `MIDAZ_TRACER_API_KEY` | Chave de API opcional para o Tracer. Quando você não a define, as chamadas ao Tracer usam o bearer token do ledger. |
| `PLUGIN_AUTH_ENABLED` | Habilita a autenticação do Access Manager (`true` ou `false`). |
| `PLUGIN_AUTH_ADDRESS` | Endereço do serviço do Access Manager. |
| `MIDAZ_CLIENT_ID` | Client ID para autenticação no Access Manager. |
| `MIDAZ_CLIENT_SECRET` | Client secret para autenticação no Access Manager. |
| `MIDAZ_TIMEOUT` | Timeout de requisição HTTP em segundos. |
| `MIDAZ_DEBUG` | Habilita logs de debug (`true` ou `false`). |
| `MIDAZ_MAX_RETRIES` | Número máximo de novas tentativas para requisições com falha. |
| `MIDAZ_IDEMPOTENCY` | Envia uma chave de idempotência aleatória em cada criação, atualização e exclusão (`true` ou `false`). Padrão: `false`. |
| `MIDAZ_ERROR_EXPOSE_BODY` | Inclui o body bruto da resposta em `*pkg/errors.Error`. |
| `MIDAZ_ACCESS_MANAGER_ALLOW_INSECURE_HTTP` | Permite HTTP simples para o Access Manager. O SDK recusa essa opção quando `MIDAZ_ENVIRONMENT=production`. |
| `MIDAZ_ALLOW_INSECURE_HTTP` | Permite HTTP simples para as URLs do ledger e do Tracer em hosts que não são loopback. O SDK recusa essa opção quando `MIDAZ_ENVIRONMENT=production`. |

Para a matriz completa de opções de `midaz`, `pkg/config` e `pkg/sdkctx`, veja o [guia de configuração](https://github.com/LerianStudio/midaz-sdk-golang/blob/main/docs/configuration.md) no repositório do SDK.

## Exemplos de projetos

***

> [!TIP]
>
> O SDK tem um conjunto numerado de tutoriais focados (exemplos 01–11), além de exemplos avançados e de referência. Cada exemplo numerado ensina um conceito. Navegue por eles no [diretório de exemplos](https://github.com/LerianStudio/midaz-sdk-golang/tree/main/examples) no GitHub.

| Exemplo | O que ele demonstra |
| :- | :- |
| `01-hello-world` | Inicialização mínima mais a primeira chamada de API. |
| `02-auth` | Autenticação do Access Manager (configuração de produção). |
| `03-end-to-end` | Criação de uma transação na `/v2` com `CreateDirect`. |
| `04-listing-cursor` | Paginação por cursor com `iter.Seq2`. |
| `05-listing-pages` | Paginação por página com `List`, `All` e `Pages`. |
| `06-idempotency` | Sem chave e chave própria. |
| `07-retries` | Política padrão, política personalizada, novas tentativas desabilitadas. |
| `08-logging-slog` | Integração com `*slog.Logger`. |
| `09-testing-with-mocks` | Uma interface estreita própria mais um mock escrito à mão. |
| `10-observability-otel` | Superfície completa de OpenTelemetry (tracing + métricas + logs). |
| `11-server-version` | Ler a versão do servidor na inicialização e atualizá-la por temporizador. |

O repositório também inclui exemplos de referência: `concurrency`, `configuration`, `context`, `tracing`, `tracing-server`, `pkg-validation-demo`, `mass-demo-generator` e `workflow-with-entities`.

## Explore as APIs

***

Para mais informações sobre as APIs, consulte os links a seguir:

> [card] [Mapeamento de API externa](https://github.com/LerianStudio/midaz-sdk-golang/blob/main/docs/mapping/external_apis.md)

> [card] [Mapeamento de API interna](https://github.com/LerianStudio/midaz-sdk-golang/blob/main/docs/mapping/internal_apis.md)

> [card] [Documentação do Godoc](https://pkg.go.dev/github.com/LerianStudio/midaz-sdk-golang/v6)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.