Skip to main content

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.

Balance Overdraft allows a balance to be debited beyond its available funds without letting the primary balance go negative. The deficit is tracked as OverdraftUsed, and Midaz automatically handles the operation split between the primary balance and an internal companion balance. When credits arrive, repayment is prioritized — the overdraft is repaid first, and any remainder flows to Available. This mechanism supports credit lines, BNPL, settlement accounts, earned wage access, and any scenario where controlled negative positions are required.

Balance direction


Balances carry a direction field that defines how debits and credits affect the balance:
DirectionBehaviorTypical use
credit (default)Debit decreases, credit increasesAsset-like balances — checking accounts, wallets, reserves
debitDebit increases, credit decreasesLiability-like balances — loans, overdraft tracking, payables
Direction is set at creation time and is immutable. The overdraft companion balance (described below) always uses direction=debit.

Balance settings


The settings object on a balance controls overdraft behavior:
FieldTypeDescription
allowOverdraftbooleanEnables overdraft on this balance
overdraftLimitEnabledbooleanGates whether a limit is enforced
overdraftLimitstring (decimal)Maximum overdraft amount. Required when overdraftLimitEnabled is true. Must be greater than 0.
A balanceScope field also exists inside settings but is system-managed — it distinguishes internal balances (like the overdraft companion) from transactional balances. You do not set this field directly.

Configuration modes


No overdraft (default)

The standard behavior. Any debit that exceeds the available balance is rejected.
{
  "key": "checking",
  "assetCode": "BRL",
  "settings": {
    "allowOverdraft": false
  }
}

Unlimited overdraft

The balance can go negative without a cap. Useful for settlement or pool accounts where negative positions are normal and reconciled externally.
{
  "key": "settlement",
  "assetCode": "USD",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": false
  }
}

Limited overdraft

The balance can go negative up to a defined limit. The most common mode for consumer credit products.
{
  "key": "checking",
  "assetCode": "BRL",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": true,
    "overdraftLimit": "5000.00"
  }
}
When overdraftLimitEnabled is true, overdraftLimit is required and must be a positive decimal string. Omitting it or setting it to "0" returns error 0172 - ErrInvalidBalanceSettings.

How overdraft works


Operation split

When a debit transaction exceeds the available funds, Midaz automatically splits the operation:
  1. The debit consumes all remaining Available, flooring it at 0.
  2. The excess is accrued as OverdraftUsed on the primary balance.
  3. A companion operation is created on the internal "overdraft" balance (described below), recording the liability as a double-entry debit.
Example: Balance has Available = 300. A debit of 500 arrives.
StepAvailableOverdraftUsedDescription
Before3000Normal state
After0200300 consumed from Available, 200 accrued as overdraft
The transaction succeeds as a single atomic operation. The caller does not need to handle the split — Midaz does it automatically.
If a limit is configured, Midaz validates that the resulting OverdraftUsed does not exceed overdraftLimit before processing. If it would, the transaction is rejected with error 0167 - ErrOverdraftLimitExceeded.

Automatic repayment (refund split)

When a credit arrives and OverdraftUsed > 0, Midaz prioritizes repayment:
  1. The credit is applied to OverdraftUsed first, reducing the debt.
  2. Any remaining amount after OverdraftUsed reaches 0 flows to Available.
  3. A companion operation on the "overdraft" balance records the repayment.
Example: OverdraftUsed = 200, Available = 0. A credit of 350 arrives.
StepAvailableOverdraftUsedDescription
Before0200Overdraft active
After1500200 repaid, 150 goes to Available
Repayment is automatic and cannot be bypassed. This ensures overdraft positions are always reduced as early as possible, keeping the balance healthy.

Cancelling a pending overdraft transaction

When a PENDING transaction that drew overdraft is cancelled, Midaz keeps the companion balance in lockstep with the primary:
  1. The cancel reverses the original hold and any overdraft drawn during the pending window — OverdraftUsed returns to its pre-pending value.
  2. A companion CREDIT operation on the "overdraft" balance shrinks the liability by the exact amount that was drawn, repaying it.
  3. Both the primary cancel and the companion credit are applied in the same atomic batch, so the primary balance and companion balance never drift out of sync — even if the cancel arrives in a high-throughput burst.
The engine calls this in-lockstep guarantee companion parity. It applies symmetrically across the hold, commit, and cancel phases of any pending transaction that touches overdraft.

Position


Every balance response includes a computed position block that provides a real-time view of the balance state:
FieldDescription
availableBalance.Available minus OverdraftUsed. Can be negative when overdraft is active.
onHoldMirrors Balance.OnHold — funds reserved by pending operations.
overdraftLimitAvailableRemaining overdraft headroom. "0" when overdraft is disabled. Omitted when unlimited. Positive decimal when a limit is configured.
The position block is never persisted — it is always computed at query time from the current balance state. Do not cache it for accounting purposes.

Companion balance


The first time allowOverdraft flips to true on a balance — at creation or via update — Midaz auto-provisions a companion balance under the same account to record the liability side of the double-entry. It is created once per account and reused across every overdraft draw and repayment.
PropertyValueWhy
key"overdraft"Reserved system key
directiondebitThe companion tracks a liability — debits grow it, credits shrink it
scopeinternalBlocks direct user operations
allowSendingtrueRequired for DEBIT operations on the companion (overdraft draws)
allowReceivingtrueRequired for CREDIT operations on the companion (overdraft repayments)
This balance is fully system-managed:
  • It cannot be created, modified, or deleted via the public API.
  • The key "overdraft" is reserved — attempting to create a balance with this key returns error 0170 - ErrReservedBalanceKey.
  • It mirrors the liability as a proper double-entry record, ensuring the ledger stays balanced.
The scope: "internal" value gates direct user operations regardless of the permission flags above — any attempt to operate on this balance directly is rejected with error 0168 - ErrDirectOperationOnInternalBalance. The companion only moves through system-driven overdraft enrichment.

Overdraft state on operations


Every operation exposes the overdraft state directly on the balance and balanceAfter blocks. The overdraftUsed field captures how much overdraft was consumed before and after the operation — providing a complete audit trail without needing a separate balance query. For operations that do not touch overdraft, both values are "0". System-managed companion operations on the "overdraft" balance are exposed with type: "OVERDRAFT" (uppercase). The direction field carries the lifecycle semantics: "debit" for a draw, "credit" for a repayment.
{
  "type": "DEBIT",
  "direction": "debit",
  "amount": { "value": "500" },
  "accountAlias": "@user123",
  "balanceKey": "checking",
  "balance": {
    "available": "300",
    "onHold": "0",
    "version": 1,
    "overdraftUsed": "0"
  },
  "balanceAfter": {
    "available": "0",
    "onHold": "0",
    "version": 2,
    "overdraftUsed": "200"
  }
}
Both the primary and the companion operation share the same overdraftUsed before/after pair — they mirror the primary balance’s overdraft transition, making the lifecycle visible from either row. The internal snapshot JSONB column on the operations table stores the same values for indexing and historical reconstruction; it is not part of the public JSON wire and surfaces on balance.overdraftUsed and balanceAfter.overdraftUsed instead. Future system-generated context can be added to the snapshot without breaking the public contract.
Companion operations inherit routeId, routeCode, and routeDescription from the primary operation that triggered them. This keeps both legs of the double-entry under the same accounting rubric — chart-of-accounts classifications flow from the primary to the companion automatically, so reports filtered by route show both sides of the overdraft.

Overdraft events


Midaz publishes lifecycle events to RabbitMQ when overdraft state changes. Publication is enabled by default — set the flag to "false" to opt out.
# Disable overdraft event publication (default: enabled).
RABBITMQ_OVERDRAFT_EVENTS_ENABLED=false

# Optional: route overdraft events to a dedicated exchange.
# When unset, the broker's default exchange is used.
RABBITMQ_OVERDRAFT_EVENTS_EXCHANGE=transaction.overdraft_events.exchange

Event types

EventDescription
overdraft.drawnOverdraft was consumed — OverdraftUsed increased
overdraft.repaidOverdraft was partially repaid — OverdraftUsed decreased but remains > 0
overdraft.clearedOverdraft was fully repaid — OverdraftUsed reached 0

Example event payload

{
  "source": "midaz",
  "eventType": "balance",
  "action": "overdraft.drawn",
  "timestamp": "2026-04-28T14:30:00.000000Z",
  "version": "v3.0.0",
  "organizationId": "0198575d-f9fd-702b-bb15-fa4c980b32c7",
  "ledgerId": "0198575d-fa0b-7ac7-8b7d-9d3ab7dccafc",
  "payload": {
    "accountId": "0198575f-a8f9-7924-a6d7-8122f2c77ddd",
    "transactionId": "019b2c3d-4e5f-6789-0123-456789abcdef",
    "amount": "200",
    "overdraftBalance": "200",
    "overdraftLimit": "5000.00",
    "timestamp": "2026-04-28T14:30:00.000000Z"
  }
}
Use overdraft events to trigger downstream workflows — interest accrual, customer notifications, risk alerts, or automatic collection processes.

Use cases


Checking account overdraft (cheque especial)

Classic consumer credit. The customer’s checking balance can go negative up to a pre-approved limit, with interest accrued on the outstanding amount.
{
  "key": "checking",
  "assetCode": "BRL",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": true,
    "overdraftLimit": "2000.00"
  }
}

Buy Now, Pay Later (BNPL)

A BNPL provider issues a purchase credit against the customer’s balance, creating an immediate overdraft position that is repaid in installments.
{
  "key": "bnpl",
  "assetCode": "BRL",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": true,
    "overdraftLimit": "10000.00"
  }
}

Earned Wage Access / Salary advance

Employees draw against future earnings. The overdraft position is cleared when payroll credits arrive.
{
  "key": "salary-advance",
  "assetCode": "BRL",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": true,
    "overdraftLimit": "3000.00"
  }
}

Marketplace receivables advance

Sellers receive an advance on future receivables. The overdraft is repaid automatically as sales settlements arrive.
{
  "key": "receivables",
  "assetCode": "BRL",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": true,
    "overdraftLimit": "50000.00"
  }
}

Settlement / Pool accounts (unlimited mode)

Settlement and pool accounts routinely go negative during intraday processing. Unlimited overdraft avoids artificial rejections while the position is reconciled by end-of-day.
{
  "key": "settlement-pool",
  "assetCode": "USD",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": false
  }
}

Revolving credit lines (B2B)

Businesses draw and repay from a revolving credit facility. The overdraft limit represents the total credit line.
{
  "key": "credit-line",
  "assetCode": "BRL",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": true,
    "overdraftLimit": "500000.00"
  }
}

Insurance pre-financing

Insurers pre-finance claims before premium collection cycles close. The overdraft covers the gap between payout and collection.
{
  "key": "claims-prefin",
  "assetCode": "BRL",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": true,
    "overdraftLimit": "100000.00"
  }
}

Loyalty programs (advanced points)

Customers redeem points before earning them. The overdraft tracks the point deficit, repaid as new points are accrued.
{
  "key": "loyalty-points",
  "assetCode": "POINTS",
  "settings": {
    "allowOverdraft": true,
    "overdraftLimitEnabled": true,
    "overdraftLimit": "10000"
  }
}

Protection rules


Overdraft introduces several immutability and access constraints to maintain ledger integrity:
  • Direction is immutable. Once set at creation, a balance’s direction cannot be changed.
  • Internal balances are read-only. The "overdraft" companion balance cannot be created, deleted, or updated via the public API. PATCH requests on internal balances are rejected with error 0175.
  • Reserved keys. The key "overdraft" is reserved for the system-managed companion balance.
  • Disabling overdraft preserves outstanding debt. Setting allowOverdraft: false while OverdraftUsed > 0 is allowed — the flag blocks future overdraft draws, while incoming credits keep repaying the existing debt until it reaches zero.
  • Limit cannot drop below usage. If OverdraftUsed = 200, setting overdraftLimit: "100" is rejected (error 0173) — repay below the new ceiling first, or set a higher limit.
  • Optimistic concurrency. Balance updates use version-based concurrency control. Stale writes are rejected with error 0174 — retry with the latest version.
For the complete catalog of overdraft-related error codes (0167–0175), see the Midaz error list.

Next steps


  • Learn about Balances — the foundation that overdraft builds on.
  • Understand Operations to trace how overdraft splits appear in the ledger.
  • Set up the Event Publisher to consume overdraft lifecycle events.
  • Explore Transactions for the full picture of double-entry accounting in Midaz.