Bonaventure OgetoBy Bonaventure Ogeto|

Human in the Loop Design for AI Payment Operations

Human-in-the-loop pattern: 1) AI agent proposes the action with its reasoning. 2) Proposal goes to human reviewer (Slack message with Approve/Reject buttons, or an admin approval queue). 3) Human approves → agent executes via the Paystack API. Human rejects → agent receives rejection and informs the user. Operations requiring human approval: any transfer above NGN 50,000, new bank recipient creation, bulk payouts, refunds to different accounts than the original payment. Operations that can be automated: payment link creation, subscription status queries, transaction lookups, refunds below threshold for verified customers.

Approval Gate Design

OperationAutomation LevelRationale
Transaction lookupFull autoRead-only, no financial impact
Payment link creationFull autoCustomer still chooses to pay; reversible
Subscription status checkFull autoRead-only
Refund < NGN 5,000 (verified customer)Auto with audit logLow value, reversible
Refund > NGN 5,000Human approval requiredMaterial value, irreversible
Transfer to allowlist recipientHuman approval above thresholdIrreversible, financial impact
New recipient creationAlways human approvalExpands allowlist — high security impact
Bulk payoutAlways human approvalMultiplied financial impact
Subscription cancellationHuman approval (churn opportunity)Revenue impact, opportunity to retain
// Approval gate middleware — wraps any write tool
async function withApproval({ action, params, threshold, agentSessionId, channel = '#payments-approvals' }) {
  // Check if this action requires approval based on params
  var requiresApproval = action === 'transfer' && params.amount > threshold
    || action === 'refund' && params.amount > 5000_00
    || action === 'create_recipient'  // always requires approval
    || action === 'bulk_transfer';    // always requires approval

  if (!requiresApproval) {
    return { approved: true, auto: true };
  }

  // Queue for human approval
  var requestId = crypto.randomUUID();
  await db.pendingApprovals.insert({ requestId, action, params, agentSessionId, status: 'pending', created_at: new Date() });

  // Notify via Slack with interactive buttons
  await sendSlackInteractiveMessage(channel, {
    text: 'AI payment action requires approval',
    blocks: buildApprovalMessage(action, params, requestId),
  });

  // Poll for approval (max 30 minutes, then escalate)
  return new Promise((resolve) => {
    var pollInterval = setInterval(async () => {
      var record = await db.pendingApprovals.get(requestId);
      if (record.status === 'approved') {
        clearInterval(pollInterval);
        resolve({ approved: true, approvedBy: record.approved_by, auto: false });
      }
      if (record.status === 'rejected') {
        clearInterval(pollInterval);
        resolve({ approved: false, rejectedBy: record.rejected_by });
      }
    }, 5000);

    // Escalate after 30 minutes without decision
    setTimeout(() => {
      clearInterval(pollInterval);
      resolve({ approved: false, reason: 'approval_timeout' });
    }, 30 * 60 * 1000);
  });
}

Learn More

Key Takeaways

  • AI proposes, human approves, AI executes — the three-step pattern for any irreversible payment action.
  • Build the approval gate at the tool layer, not the prompt layer — so it cannot be bypassed by prompt manipulation.
  • Use Slack interactive messages or an admin UI queue for approval — out-of-band channels are more secure than in-chat confirmation.
  • Set clear SLAs for human review — if approval takes too long, the AI should escalate, not auto-proceed.
  • Log every proposal, approval, rejection, and execution with timestamps and approver identity.

Frequently Asked Questions

What if the human reviewer is unavailable and the action is time-sensitive?
Design an escalation path: if the primary approver has not responded in X minutes, escalate to a secondary approver or a manager. If neither responds within the timeout window, the action is rejected automatically and the user is notified that manual intervention is required. Never auto-proceed after timeout — the absence of approval is a rejection by default.
Can the AI agent provide a recommendation alongside the approval request?
Yes — and it should. The approval request should include: what action is proposed, the AI's reasoning, relevant context (customer history, normal pattern for this type of transaction), and any risk signals. A well-contextualized approval request takes a human reviewer 30 seconds instead of 5 minutes. The AI's job is to make human review faster, not to push humans to approve blindly.
Is in-chat approval (customer says "confirm") secure enough for payment actions?
Not for significant amounts. In-chat confirmation can be bypassed by prompt injection — a crafted user message might manipulate the agent into treating an earlier message as a confirmation. Out-of-band approval (Slack message to your team, admin UI button) is more secure because it requires a human with system access to take action, not just a message in the same conversation thread.

Ready to build real-world apps?

Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.

Apply to the McTaba Marathon