Escrow and the ledger

How funds lock before a task exists, why Hannu never holds the money, and how an append-only double-entry ledger records every move.

Money commits before work begins. When you create a task, the price is locked in escrow before the task exists — the write that creates the task and the lock is one atomic step. An Operator never starts on an unfunded task, and you never owe money you didn't set aside.

Money is integers

Every amount is an integer in the currency's minor unit — kobo for Naira, cents for dollars. A reward_minor of 250000 is ₦2,500.00. There are no floats anywhere in the money path: floats round, and rounding loses money. When you read or send an amount, you're reading or sending whole minor units.

JSON
{
  "reward_minor": "250000",
  "currency": "NGN"
}

Hannu never holds the funds

Hannu is not a custodian. Licensed partners hold the actual money; our system records who is owed what. What we keep is an append-only double-entry ledger — every movement is written as balanced debit and credit entries, and entries are never edited or deleted. A mistake is corrected by writing a new, reversing entry, not by changing the original. The history is the source of truth, and it stays complete.

Why append-only

An append-only ledger means the record of a payment can always be reconstructed and audited. Because corrections are new entries rather than edits, there is no way to quietly rewrite what happened — every state the money passed through remains visible.

Escrow-lock states

Behind each task is one escrow lock, which moves through these states as the money settles. The lock is internal bookkeeping — it isn't serialized on the task, so you read the task's own state and your wallet balance rather than a lock field:

  • locked — funds are reserved against the task at creation. They are committed to this task and can't be spent elsewhere.
  • partial — part of the lock has been released — for example one slot of a multi-worker task — while the remainder stays held.
  • released — the task was approved and the Operator has been paid. The ledger records the transfer out of escrow.
  • disputed_frozen — proof was rejected and a dispute is open. Funds stay put, released to neither side, until the dispute resolves.

A refund — when a task is cancelled before acceptance, or a dispute resolves in your favour — returns funds to your wallet through the ledger. It is a task and ledger outcome, not a lock state. Each transition is a ledger event, so the balance on your wallet and the state on the task always agree.

The flow

  1. You call POST /v1/tasks. Escrow locks in the same transaction that creates the task.
  2. An Operator completes the work and submits proof.
  3. You approve and escrow releases to the Operator, or you reject and escrow freezes while a dispute runs.
  4. Cancel before acceptance and escrow refunds to your wallet.

The AI verification layer is never in this path — it produces a report, but releasing, freezing, or refunding money is a decision your approval drives, not the model. See Proof and verification.