Architecture: 1) Authenticate the user first — verify their email or phone number before the chatbot can access their payment data. 2) Define customer-scoped tools: get_customer_transactions(email), get_subscription_status(subscription_code), get_transaction_by_reference(ref). 3) Pass the verified customer email + tools to the LLM. 4) LLM can only see that customer's data — not other customers. 5) Chatbot is read-only. Any refund or cancellation request goes to a human support agent queue.
// Customer-scoped tools — all queries filter by verified customer email
function buildCustomerTools(verifiedEmail) {
return [
{
name: 'get_my_transactions',
description: 'Get recent transactions for this customer.',
input_schema: {
type: 'object',
properties: {
status: { type: 'string', enum: ['success', 'failed', 'pending'] },
limit: { type: 'number' },
},
},
},
{
name: 'get_transaction_by_reference',
description: 'Look up a specific transaction by reference code.',
input_schema: {
type: 'object',
properties: { reference: { type: 'string' } },
required: ['reference'],
},
},
{
name: 'get_subscription_status',
description: 'Check the status of a subscription.',
input_schema: {
type: 'object',
properties: { subscription_code: { type: 'string' } },
required: ['subscription_code'],
},
},
{
name: 'request_human_agent',
description: 'Escalate to a human support agent for refunds, cancellations, or complex issues.',
input_schema: {
type: 'object',
properties: { reason: { type: 'string' } },
required: ['reason'],
},
},
];
}
// Tool execution — always enforces the verified email scope
async function executeSupportTool(toolName, input, verifiedEmail) {
var headers = { Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY };
if (toolName === 'get_my_transactions') {
var params = 'customer=' + encodeURIComponent(verifiedEmail) + '&perPage=' + (input.limit || 10);
if (input.status) params += '&status=' + input.status;
var res = await fetch('https://api.paystack.co/transaction?' + params, { headers });
return (await res.json()).data;
}
if (toolName === 'get_transaction_by_reference') {
var res = await fetch('https://api.paystack.co/transaction/verify/' + input.reference, { headers });
var data = (await res.json()).data;
// Security: only return if this transaction belongs to the verified customer
if (data?.customer?.email !== verifiedEmail) {
return { error: 'Transaction not found for your account' };
}
return data;
}
if (toolName === 'request_human_agent') {
await db.supportQueue.insert({ customerEmail: verifiedEmail, reason: input.reason, ts: new Date() });
return { status: 'queued', message: 'A human agent will contact you within 2 business hours' };
}
}
See using an LLM to explain failed payments for the failure code explanation pattern to include in your chatbot system prompt.
KES 2,999
The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.
Start Paystack Course