Architecture: 1) Define tools for Paystack queries (list_transactions with date/channel/status filters, get_plan_subscriptions, get_settlements). 2) User types a natural language question. 3) LLM translates intent to tool calls — e.g., "last month revenue" → list_transactions({from: "2026-06-01", to: "2026-06-30", status: "success"}). 4) Tool results returned to LLM for aggregation and plain-English response. 5) Keep the dashboard read-only — no write tools in this context.
// Tools for the natural language revenue dashboard
const dashboardTools = [
{
name: 'get_revenue_summary',
description: 'Get total revenue, transaction count, average order value, and channel breakdown for a date range.',
input_schema: {
type: 'object',
properties: {
from: { type: 'string', description: 'Start date YYYY-MM-DD' },
to: { type: 'string', description: 'End date YYYY-MM-DD' },
},
required: ['from', 'to'],
},
},
{
name: 'get_top_customers',
description: 'Get the top customers by total spend in a date range.',
input_schema: {
type: 'object',
properties: {
from: { type: 'string' },
to: { type: 'string' },
limit: { type: 'number', description: 'Number of customers, default 10' },
},
required: ['from', 'to'],
},
},
{
name: 'get_subscription_mrr',
description: 'Get Monthly Recurring Revenue from active Paystack subscriptions.',
input_schema: { type: 'object', properties: {} },
},
];
// Server-side: compute summaries, not raw data
async function executeRevenueTool(toolName, input) {
var headers = { Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY };
if (toolName === 'get_revenue_summary') {
// Fetch all transactions in range (paginate for large volumes)
var url = 'https://api.paystack.co/transaction?status=success&from=' + input.from + '&to=' + input.to + '&perPage=100';
var txns = (await (await fetch(url, { headers })).json()).data || [];
// Compute server-side — do not send raw array to LLM
var total = txns.reduce((sum, t) => sum + t.amount, 0);
var byChannel = txns.reduce((acc, t) => {
acc[t.channel] = (acc[t.channel] || 0) + t.amount;
return acc;
}, {});
return {
total_kobo: total,
total_ngn: total / 100,
transaction_count: txns.length,
average_order_ngn: txns.length ? total / 100 / txns.length : 0,
by_channel: Object.fromEntries(Object.entries(byChannel).map(([k, v]) => [k, v / 100])),
};
}
if (toolName === 'get_subscription_mrr') {
var subs = (await (await fetch('https://api.paystack.co/subscription?status=active&perPage=100', { headers })).json()).data || [];
var mrr = subs.reduce((sum, s) => sum + s.amount, 0) / 100;
return { mrr_ngn: mrr, active_subscriptions: subs.length };
}
}
See building a Paystack query agent for the underlying tool calling pattern.
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