Embedding Payment Actions in an AI Customer Service Workflow
Tiered tool design: Tier 1 (auto-execute): get_transaction, get_subscription_status, list_customer_payments — safe to run without human review. Tier 2 (require human confirmation): initiate_refund, cancel_subscription, create_payment_link for existing debt — agent proposes, human approves, agent executes. Never let write tools auto-execute in a customer service context. Confirmation can be a Slack approval message, admin UI queue, or explicit customer "confirm" reply in the same chat thread, depending on the action's reversibility.
Tiered Tool Design for Customer Service
// Tier 1: auto-execute (read-only)
var readTools = [
{ name: 'get_transaction', description: 'Get transaction details by reference.' /* ... */ },
{ name: 'get_subscription_status', description: 'Check subscription status.' /* ... */ },
{ name: 'list_recent_payments', description: 'List customer's recent payments.' /* ... */ },
];
// Tier 2: require approval (write operations)
var writeTools = [
{
name: 'request_refund',
description: 'Request a refund for a transaction. Queues for human approval — does not execute immediately.',
input_schema: {
type: 'object',
properties: {
transaction_reference: { type: 'string' },
reason: { type: 'string' },
amount: { type: 'number', description: 'Amount in kobo. Omit for full refund.' },
},
required: ['transaction_reference', 'reason'],
},
},
{
name: 'request_subscription_cancellation',
description: 'Request cancellation of a subscription. Queues for human approval.',
input_schema: {
type: 'object',
properties: { subscription_code: { type: 'string' }, reason: { type: 'string' } },
required: ['subscription_code', 'reason'],
},
},
];
// Execute write tools — always queue, never execute immediately
async function executeWriteTool(toolName, input, customerId, agentSessionId) {
var requestId = await db.pendingActions.insert({
tool: toolName,
input,
customer_id: customerId,
agent_session_id: agentSessionId,
status: 'awaiting_approval',
created_at: new Date(),
});
// Notify human team via Slack
await sendSlackMessage({
channel: '#support-approvals',
text: 'AI refund request from customer ' + customerId + ': ' + JSON.stringify(input),
blocks: [
{ type: 'section', text: { type: 'mrkdwn', text: '*Action:* ' + toolName + '
*Params:* ' + JSON.stringify(input) } },
{
type: 'actions',
elements: [
{ type: 'button', text: { type: 'plain_text', text: 'Approve' }, value: requestId, action_id: 'approve_action' },
{ type: 'button', text: { type: 'plain_text', text: 'Reject' }, value: requestId, action_id: 'reject_action', style: 'danger' },
],
},
],
});
return { status: 'queued', requestId, message: 'Your request has been submitted and will be processed within 2 business hours.' };
}
When the human approves via Slack, your Slack webhook handler executes the actual Paystack API call and updates the customer.
Learn More
See human-in-the-loop design for AI payment operations for the broader framework.
Key Takeaways
- ✓Read tools (lookup, status check) can auto-execute. Write tools (refund, cancel, charge) need human confirmation.
- ✓Build an approval queue — agent proposes action, human approves or rejects, agent executes only after approval.
- ✓Log every proposed and executed action with the agent session ID and the human who approved.
- ✓An AI that auto-refunds is a liability — even one wrong refund erases the cost savings of automation.
- ✓Out-of-band confirmation (Slack DM to team) is more secure than in-chat confirmation.
Frequently Asked Questions
- What if the customer asks for a refund urgently and cannot wait for human approval?
- Set an auto-approve threshold: refunds below NGN 2,000 from verified good-standing customers can be auto-approved and executed immediately. Above the threshold, human review is required. Log both auto-approved and human-approved actions the same way. Make the threshold a configuration constant, not something the AI can change.
- Can the AI cancel a subscription without human approval?
- No — subscription cancellation is irreversible (the customer loses access) and has revenue impact. Always route to human approval. The AI can confirm the cancellation request was received and provide an expected timeline. This is also a churn-save opportunity: a human reviewing the cancellation request can offer a discount or alternative plan.
- How do I connect the Slack approval button back to the Paystack refund execution?
- Slack sends a payload to your interactivity URL when a button is clicked. Parse the action_id and value (request_id) from the payload, look up the pending action in your database, and execute the Paystack API call. Update the Slack message with the outcome. This is your human-in-the-loop execution loop — it requires a webhook endpoint for Slack interactivity on your server.
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