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

# Core concepts

> The money model — basis points, minor units, the split algorithm, tax — and the permission model.

## Money is exact, never floating

Every amount in Disbursement is an **integer**. There are no floats anywhere in
the config or the math, because the output is a file a bank executes — a
rounding error creates or destroys real money.

* **Percentages are basis points (bps).** 1% = 100 bps, so 100.00% = 10000 bps.
  A 90/10 split is `9000` / `1000`.
* **Amounts are minor units.** Values are stored and computed in the currency's
  minor unit (x100 convention). The **exporter** owns display formatting per the
  bank spec; storage never changes.
* **Round half up** for MDR, service charge, and tax.

## The split algorithm

For a gross amount `G` and a resolved config, the engine computes:

<Steps>
  <Step title="Fees">
    `mdr = rhu(G × mdr_bps / 10000)`, then the service charge (a percentage of
    gross or a fixed minor-unit amount). `fee = mdr + service_charge`.
  </Step>

  <Step title="Tax">
    Tax is configurable: a `base` (fees or gross) × `mode` (include or exclude) ×
    `payer` (merchant or klikit). `exclude` adds tax on top; `include` backs it
    out so `net_of_tax + tax == base`.
  </Step>

  <Step title="Distributable pool">
    Deduct the merchant-borne fee and tax from gross to get the pool `P`.
    klikit-borne portions are reported separately as `klikit_absorbed_*` and
    never touch the merchant pool. A **negative** pool (fees exceed gross) is
    flagged, never clamped — the batch can't be approved until it's resolved.
  </Step>

  <Step title="Largest-remainder split">
    Each party gets `floor(P × bps / 10000)`; the leftover minor units are handed
    out one at a time by descending fractional remainder. This guarantees the
    shares sum to `P` **exactly** — independent per-line rounding is forbidden.
  </Step>
</Steps>

<Note>
  **Worked example (IDR).** Gross Rp 100,000.00 (`10,000,000` minor units), MDR
  150 bps, fixed service charge `250,000`, 11% tax excluded on fees, merchant
  bears both. Fee = `400,000`, tax = `44,000`, pool = `9,556,000`. A 9000/1000
  split → `8,600,400` + `955,600` = `9,556,000` exactly.
</Note>

## Config validation

A template's config is rejected unless:

* `Σ split_bps == 10000` (exactly 100%),
* exactly **one** party has role `merchant`, at most **one** has role `klikit`,
* no negative or non-integer values.

## Line flags

After compute, each line may carry flags that block approval until resolved:

| Flag              | Meaning                                                 |
| ----------------- | ------------------------------------------------------- |
| `negative_net`    | Fees exceed gross for this input; the pool is negative. |
| `no_bank_details` | A payable party has no bank row on the instance.        |
| `unmatched_input` | A gross input didn't match any active instance.         |

## Permissions

Three distinct permissions gate the workflow (approval is always separate from
operation — maker-checker):

| Permission                   | Grants                                                                         |
| ---------------------------- | ------------------------------------------------------------------------------ |
| `disburseit.finance.operate` | Create/edit templates & instances, create/compute/export batches.              |
| `disburseit.finance.approve` | Approve a computed batch, verify parties, approve/reject bank-change requests. |
| `disburseit.bank-pii.edit`   | View and edit full (unmasked) bank account details.                            |

## Data safety

* Bank account numbers live **only** on the instance's parties, encrypted at
  rest, masked (last-4) in ordinary reads, full access role-gated and audited.
* A batch's config is **frozen at compute** — later template edits can never
  change a computed batch. The beneficiary bank details are snapshotted onto
  each line too, so a post-approval bank edit can't silently redirect a payment.
* An **exported** batch can never be voided (money may have moved; the record is
  permanent).
