Building a Payments Support Chatbot on Paystack Data
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.
Support Chatbot Architecture
// 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' };
}
}
Learn More
See using an LLM to explain failed payments for the failure code explanation pattern to include in your chatbot system prompt.
Key Takeaways
- ✓Authenticate the customer before the chatbot can access any Paystack data — no anonymous payment lookups.
- ✓Scope all tool calls to the verified customer's email — never allow cross-customer data access.
- ✓Keep the chatbot read-only — refunds and cancellations go to a human queue.
- ✓Give the LLM plain-English failure code explanations as a reference in the system prompt.
- ✓Log every chatbot session with the customer identifier, questions asked, and tools called.
Frequently Asked Questions
- How do I authenticate the customer before giving the chatbot access to their data?
- Use your existing session authentication. If the customer is logged in to your application, their verified email is in the session — pass it as the scope for the chatbot. If the chatbot is on a public widget, require the customer to enter their email and send an OTP to verify it before opening the chat session. Never trust a customer-supplied email without verification.
- What should the chatbot do when it cannot find the transaction?
- Return an honest response: "I could not find a transaction with that reference on your account." Then offer the request_human_agent option. Never let the LLM speculate about why a transaction is missing — it can produce plausible but wrong explanations. Missing transactions warrant a human check.
- Should I include refund capabilities in the chatbot?
- No — not as an automated action. A confused or manipulated LLM can refund the wrong transaction. Build a refund request tool that queues the request for human review. The chatbot can confirm the refund request was received and provide a timeline, but a human approves and executes the actual refund via Paystack dashboard or API.
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