Require human approval for transfers
The §7.8 human-in-the-loop gate sits in front of every tool call that moves money. This guide walks through the full lifecycle: turning it on per Tool Group, the first-time PIN setup, the modal the user sees, the 60-second window, and what shows up in the audit log on approval and on timeout.
~8 min read
Why HITL is the default
Tracent operates under a §2.2 mandate: every fund movement waits for explicit human approval before it executes. This is how we satisfy the Central Bank of Nigeria's expectation that no autonomous agent moves money on its own, and it is the differentiator that lets African banks treat agentic platforms as trustworthy.
The gate is not an interruption to bolt on later. It is the default state of every new Tool Group: hitl_required ships as true on creation. Opting out is a deliberate decision for a specific group of read-only tools; it is not the path of least resistance.
Turning HITL on for a Tool Group
From /console/tool-groups, select the group and look at the right-hand policy panel. The Require human approval toggle is third from the top. Flip it on and click Save policy.
The save snapshots into tool_group_versions with a change summary noting the HITL toggle. The History panel shows the diff if anyone audits the change later. From the next call onwards, every tool in this group routes through the gate.
Setting a PIN the first time
The PIN is per-user, not per-organisation. The first time a user encounters the gate, the modal flips inline to a PIN- setup flow before approving the pending action:
- The modal opens with the transaction summary and a countdown.
- Underneath the summary, instead of an "Enter PIN" field, the modal shows two fields: a new 4-digit PIN and a confirmation.
- The user types both, clicks Save PIN. The value is hashed with bcrypt via pgcrypto's
crypt()through theset_user_pinSECURITY DEFINER RPC; the plain PIN never leaves the request handler, never lands in any log line. - The modal switches to the confirmation view: the same countdown, an "Enter PIN" field, and an Approve button.
The PIN persists across sessions and devices. A user who changes their PIN does so from /console/settings(the Account tab) once that surface ships; until then, the modal's set-PIN flow reappears if a user clears their pin_hash through a SQL fix.
The approval flow in practice
When an agent calls a HITL-required tool through the gateway, the gateway short-circuits the dispatch:
- A new row lands in
hitl_pendingwith the correlation ID, the user who triggered it, the tool name, and a 60-second expiry. - A row lands in
gateway_logswithstatus: hitl_pendingso the audit stream reflects the pending state in real time. - The user's console (or wherever the call originated) opens the §7.8 modal with the transaction summary and the countdown.
- On Approve:
confirm_hitlverifies the PIN against the bcrypt hash, flips thehitl_pendingrow toconfirmed, and the gateway_logs row reconciles tosuccess. The partner MCP server then receives the call. - On Cancel: the user dismisses the modal. The hitl_pending row moves to
cancelled; the gateway_logs row moves toerrorwith the message "Cancelled by user". - On timeout (60 seconds elapsed): both rows flip to
expired; the gateway_logs status becomeserror. The user has to retry the action.
What lands in the audit log
The audit log on /console/audit shows every state transition live. For a HITL-gated call you see:
- A row with
status: hitl_pendingas the call begins. - The same row's status field updates to
successorerrorwhen the gate resolves. The realtime subscription picks up the update; the row does not duplicate. redacted_keysreflects what the redactor caught from the payload before logging. The PIN itself is never in the payload because it lives only in the modal's confirmation request.
For regulator reporting, the NDPC export at /api/console/reports/ndpc separately counts successful, errored, and pending calls; the CBN export surfaces HITL-required-but-cancelled calls so an auditor can tell when the gate was the reason a transfer did not happen.
Which tools should require HITL
The rule of thumb is: any tool whose execution is hard to reverse should require HITL. Concretely:
- Yes:
initiate_transfer,create_charge,refund,create_payout,send_message(where it moves customer-visible state),register_account. - No:
verify_transaction,check_balance,fetch_account_status,list_transactions,get_invoice.
The grouping decision lives at the Tool Group level. Read-only tools belong in a separate group with HITL off; write tools stay in a HITL-required group. The composer at /console/tool-groups lets you split tools by dragging them across groups; the change versions into tool_group_versions like any other.
What is coming in Phase 2
The 4-digit PIN is the Phase 1 implementation. Phase 2 adds WebAuthn biometric integration so a user's fingerprint or face is the approval primitive on supported devices, with the PIN as a fallback. The contract on the gateway side does not change: the gate is still per-call, the audit-log shape is identical, the 60-second timeout still applies. Customer- merchants do not need to change anything to benefit from the upgrade.
Push-notification fallback to a user's mobile device is the second Phase 2 enhancement; the gate's timeout extends to whatever the mobile client's notification system allows.
Where to go from here
- Configure a Tool Group policy for the rest of the policy controls beside HITL.
- Read and export the audit log shows how HITL state transitions surface to auditors and regulators.
- The Compliance Centre at
/console/compliancesurfaces HITL-cancelled calls as part of the trailing-24h NDPA telemetry.
Tracent Technologies