Balance direction
Balances carry a
direction field that defines how debits and credits affect the balance:
At creation, Midaz uses an explicit
direction when provided, then the Account Type’s defaultDirection. If neither is set, external Accounts use debit; all other Accounts use credit.
You set direction at creation time. It is immutable. The overdraft companion balance (described below) always uses
direction=debit.Balance settings
The
settings object on a balance controls overdraft behavior:
The
settings object also carries balanceScope. It identifies a transactional balance (the default) or a system-managed internal balance, such as the overdraft companion. You can set balanceScope: "transactional" when you create or update a public balance. You cannot set balanceScope: "internal" through the public API.Configuration modes
No overdraft (default)
The standard behavior. Midaz rejects any debit that exceeds the available balance.Unlimited overdraft
The derived position can go negative without a cap. The persistedAvailable balance remains at 0, while Midaz tracks the deficit as OverdraftUsed. Use this for settlement or pool accounts, where negative positions are normal and you reconcile them externally.
Limited overdraft
The derived position can go negative up to a defined limit. The persistedAvailable balance remains at 0, while Midaz tracks the deficit as OverdraftUsed. This is the most common mode for consumer credit products.
How overdraft works
Operation split
When a debit transaction exceeds the available funds, Midaz automatically splits the operation:- The debit consumes all remaining Available and floors it at 0.
- Midaz accrues the excess as OverdraftUsed on the primary balance.
- If Midaz finds the internal
"overdraft"balance (described below), it creates a companion operation. This operation records the liability as a double-entry debit. If it cannot find that balance, Midaz skips the companion operation; the primary balance still accrues OverdraftUsed.
The transaction succeeds as a single atomic operation. The caller does not need to handle the split — Midaz does it automatically.
If you configure a limit, Midaz checks the resulting OverdraftUsed against
overdraftLimit before it processes the transaction. If the result exceeds the limit, Midaz rejects the transaction with error 0167 - ErrOverdraftLimitExceeded.Automatic repayment (refund split)
When a credit arrives andOverdraftUsed > 0, Midaz prioritizes repayment:
- Midaz applies the credit to OverdraftUsed first and reduces the debt.
- Any remaining amount after OverdraftUsed reaches 0 flows to Available.
- If Midaz finds the internal
"overdraft"balance, a companion operation on it records the repayment. If it cannot find that balance, Midaz skips the companion operation; the credit still repays OverdraftUsed on the primary balance.
Cancelling a pending overdraft transaction
When you cancel aPENDING transaction that drew overdraft:
- The cancel reverses the original hold and any overdraft drawn during the pending window.
OverdraftUsedreturns to its value before the hold. - If Midaz finds the internal
"overdraft"balance, a companionCREDIToperation on it shrinks the liability by the exact amount drawn. If it cannot find that balance, Midaz skips the companion operation; the primary cancel still restoresOverdraftUsed. - When Midaz creates the companion credit, it applies the primary cancel and the companion credit in the same atomic batch, so the two balances do not drift.
"overdraft" balance exists, Midaz keeps it in step with the primary balance across the hold, commit, and cancel phases of any pending transaction that touches overdraft.
Position
Every balance response includes a computed
position block. It gives a real-time view of the balance state:
Companion balance
When you update a balance to set
allowOverdraft to true for the first time, Midaz auto-provisions a companion balance under the same account. The companion balance records the liability side of the double-entry. Midaz creates it once per account and reuses it across every overdraft draw and repayment.
This balance is fully system-managed:
- You cannot create, modify, or delete it through the public API.
- Midaz reserves the key
"overdraft". A request that creates a balance with this key returns error0170 - ErrReservedBalanceKey. - It mirrors the liability as a proper double-entry record, so the ledger stays balanced.
The
scope: "internal" value blocks direct user operations, regardless of the permission flags above. Midaz rejects any direct operation on this balance with error 0168 - ErrDirectOperationOnInternalBalance. The companion moves only through system-driven overdraft enrichment.Overdraft state on operations
Every operation exposes the overdraft state on the
balance and balanceAfter blocks. The overdraftUsed field records the overdraft consumed before and after the operation. This gives a complete audit trail without a separate balance query.
For operations that do not touch overdraft, both values are "0".
System-managed companion operations on the "overdraft" balance use type: "OVERDRAFT" (uppercase). The direction field carries the lifecycle: "debit" for a draw, "credit" for a repayment.
overdraftUsed before/after pair. They mirror the primary balance’s overdraft transition, so the lifecycle is visible from either row. The internal snapshot JSONB column on the operations table stores the same values for indexing and historical reconstruction. This column is not part of the public JSON wire. The values surface on balance.overdraftUsed and balanceAfter.overdraftUsed instead. Midaz can add future system-generated context to the snapshot without breaking the public contract.
Overdraft events
At runtime, Midaz enables overdraft-event publication unless
RABBITMQ_OVERDRAFT_EVENTS_ENABLED is explicitly false. The bundled example environment sets the flag to false; a deployment that starts from that example publishes no overdraft events until you set it to true.
Event types
Example event payload
Use cases
Checking account overdraft (cheque especial)
Classic consumer credit. The checking account’s derived position can go negative up to a pre-approved limit; the persistedAvailable balance remains at 0 and the outstanding amount is tracked as OverdraftUsed.
Buy Now, Pay Later (BNPL)
A BNPL provider issues a purchase credit against the customer’s balance. This creates an immediate overdraft position that the customer repays in installments.Earned Wage Access / Salary advance
Employees draw against future earnings. Payroll credits clear the overdraft position when they arrive.Marketplace receivables advance
Sellers receive an advance on future receivables. Midaz repays the overdraft automatically as sales settlements arrive.Settlement / Pool accounts (unlimited mode)
Settlement and pool accounts routinely go negative during intraday processing. Unlimited overdraft avoids artificial rejections while you reconcile the position by end-of-day.Revolving credit lines (B2B)
Businesses draw and repay from a revolving credit facility. The overdraft limit represents the total credit line.Insurance pre-financing
Insurers pre-finance claims before premium collection cycles close. The overdraft covers the gap between payout and collection.Loyalty programs (advanced points)
Customers redeem points before they earn them. The overdraft tracks the point deficit and clears as customers accrue new points.Protection rules
Overdraft introduces several immutability and access constraints to maintain ledger integrity:
- Direction is immutable. Once you set a balance’s
directionat creation, you cannot change it. - Internal balances block writes. You cannot create, delete, or update the
"overdraft"companion balance through the public API — a PATCH returns error0175. - Reserved keys. Midaz reserves the key
"overdraft"for the system-managed companion balance. - Disabling overdraft preserves outstanding debt. You can set
allowOverdraft: falsewhileOverdraftUsed > 0to block future draws, while incoming credits still repay the existing debt. - Limit cannot drop below usage. If
OverdraftUsed = 200, Midaz rejectsoverdraftLimit: "100"with error0173, so repay below the new ceiling first or set a higher limit. - Optimistic concurrency. Balance updates use version-based concurrency control, and Midaz rejects a stale write with error
0174— retry with the latest version.
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.

