# Directory Structure
```
├── .github
│ └── workflows
│ └── publish.yml
├── .gitignore
├── .idx
│ └── dev.nix
├── .vscode
│ ├── extensions.json
│ └── settings.json
├── bin
│ └── generate-openapi-typescript
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── server.json
├── src
│ ├── client
│ │ ├── client.ts
│ │ ├── http
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── lib
│ │ │ ├── checkout.ts
│ │ │ ├── plan.ts
│ │ │ └── transactions.ts
│ │ ├── middleware
│ │ │ └── authMiddlewareV3.ts
│ │ ├── schema.ts
│ │ ├── specs
│ │ │ └── v3
│ │ │ ├── checkout.yaml
│ │ │ ├── plan.yaml
│ │ │ └── transactions.yaml
│ │ └── types
│ │ ├── v3
│ │ │ ├── checkout.d.ts
│ │ │ ├── plans.d.ts
│ │ │ └── transactions.d.ts
│ │ └── v3.d.ts
│ ├── config
│ │ └── index.ts
│ ├── index.ts
│ ├── prompts
│ │ ├── index.ts
│ │ └── transactions.ts
│ ├── server.ts
│ ├── tools
│ │ ├── checkout.ts
│ │ ├── get_transaction_timeline.ts
│ │ ├── index.ts
│ │ ├── plan.ts
│ │ ├── required.ts
│ │ ├── retry_transaction.ts
│ │ └── transaction.ts
│ └── types
│ ├── checkout
│ │ ├── index.ts
│ │ └── schema.ts
│ ├── index.ts
│ ├── plan
│ │ └── schema.ts
│ └── transaction
│ └── schema.ts
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
/node_modules
/build
src/example.ts
.mcpre*
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
# mcp-flutterwave
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that enables AI assistants to interact with Flutterwave, providing tools for confirming transactions, send failed hooks, and more.
## Warning!!!
This MCP is in active development.
## Features
- Confirm Transactions (Already included)
- Retry Failed Transactions (Automatically retry transactions with recoverable errors) [✓]
- Retrieve Transaction History (Fetch and analyze past transactions) [✓]
- Send Failed Hooks (Already included)
- Generate Payment Links [✓]
- Automated Customer Support (AI chatbot integrated with Flutterwave for transaction inquiries) [✓]
## Available Tools
- `get-transactions`: Get the final status of a transaction with a transaction ID
- `resent-failed-webhook`: Resend failed webhook for a transaction
- `create-checkout`: Create a payment link for customers
- `disable-checkout`: Disable a checkout transaction link
- `retry-transaction`: Analyze and provide guidance for retrying a failed transaction
- `get-transaction-timeline`: Get the timeline/history of events for a transaction
## Installation
### Via npm (Recommended)
```bash
npm install -g mcp-flutterwave
```
### Via GitHub
```bash
git clone https://github.com/bajoski34/mcp-flutterwave.git
cd mcp-flutterwave
npm install
npm run build
```
## Usage with Claude Desktop
Add the following to your `claude_desktop_config.json`. See [here](https://modelcontextprotocol.io/quickstart/user) for more details.
### Using npm installation
```json
{
"mcpServers": {
"flutterwave": {
"command": "mcp-flutterwave",
"args": [
"--tools=create_checkout,disable_checkout,read_transaction,resend_transaction_webhook"
],
"env": {
"FLW_SECRET_KEY": "YOUR_SECRET_KEY"
}
}
}
}
```
### Using local build
```json
{
"mcpServers": {
"flutterwave": {
"command": "node",
"args": [
"/path/to/mcp-flutterwave/build/index.js",
"--tools=create_checkout,disable_checkout,read_transaction,resend_transaction_webhook"
],
"env": {
"FLW_SECRET_KEY": "YOUR_SECRET_KEY"
}
}
}
}
```
## Setup Steps
1. **Install the package**
```bash
npm install -g mcp-flutterwave
```
2. **Get your Flutterwave secret key**
- Log into your Flutterwave dashboard
- Go to Settings > API Keys
- Copy your Secret Key
3. **Configure Claude Desktop**
- Add the configuration to your `claude_desktop_config.json`
- Replace `YOUR_SECRET_KEY` with your actual Flutterwave secret key
4. **Start using with Claude**
- Open Claude Desktop
- Ask questions related to Flutterwave transactions, payments, etc.
## Contributing
We welcome contributions! Please read our [Contributing Guide](./CONTRIBUTING.md) for details on how to get started, development guidelines, and how to submit changes.
```
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
```markdown
# Contributing to mcp-flutterwave
Thank you for your interest in contributing to mcp-flutterwave! This document provides guidelines and information for contributors.
## Getting Started
### Prerequisites
- Node.js (v18 or higher)
- npm or yarn
- A Flutterwave account with API access
- Basic knowledge of TypeScript and the Model Context Protocol (MCP)
### Development Setup
1. **Fork and clone the repository**
```bash
git clone https://github.com/your-username/mcp-flutterwave.git
cd mcp-flutterwave
```
2. **Install dependencies**
```bash
npm install
```
3. **Set up environment variables**
```bash
cp .env.example .env
# Add your Flutterwave secret key
echo "FLW_SECRET_KEY=your_secret_key_here" >> .env
```
4. **Build the project**
```bash
npm run build
```
5. **Test the MCP server**
```bash
node build/index.js --tools=all
```
## Development Guidelines
### Code Style
- Use TypeScript for all new code
- Follow the existing code style and formatting
- Use meaningful variable and function names
- Add JSDoc comments for public APIs
- Ensure proper error handling
### Project Structure
```
src/
├── client/ # Flutterwave API client
│ ├── http/ # HTTP client configuration
│ ├── lib/ # API endpoint implementations
│ ├── specs/ # OpenAPI specifications
│ └── types/ # Generated TypeScript types
├── config/ # Configuration files
├── tools/ # MCP tool implementations
├── types/ # Type definitions and schemas
└── server.ts # MCP server setup
```
### Adding New Tools
1. **Create the tool implementation** in `src/tools/`
```typescript
// src/tools/your-tool.ts
import { server } from "../server.js";
import { z } from "zod";
export async function yourToolFunction(params: YourParams) {
// Implementation
return {
content: [{ type: "text" as const, text: "Result" }]
};
}
export function registerYourTool() {
server.tool(
"your.tool.name",
"Description of your tool",
YourParamsSchema.shape,
async (args) => {
return await yourToolFunction(args);
}
);
}
```
2. **Add the schema** in `src/types/your-tool/schema.ts`
```typescript
import { z } from "zod";
export const YourParamsSchema = z.object({
param1: z.string().min(1, "Required parameter"),
param2: z.number().optional()
});
```
3. **Register the tool** in `src/registered-tools.ts`
4. **Update documentation** and tool lists in relevant files
### API Client Development
When adding new Flutterwave API endpoints:
1. **Add OpenAPI spec** in `src/client/specs/v3/`
2. **Generate types** using `npm run build:types`
3. **Implement client class** in `src/client/lib/`
4. **Export from main client** in `src/client/index.ts`
### Testing
- Write unit tests for new functionality
- Test with actual Flutterwave API when possible
- Ensure error handling works correctly
- Test MCP tool integration with Claude Desktop
### Commit Guidelines
- Use conventional commit messages:
- `feat:` for new features
- `fix:` for bug fixes
- `docs:` for documentation changes
- `refactor:` for code refactoring
- `test:` for adding tests
- `chore:` for maintenance tasks
Example:
```
feat: add subscription management tools
fix: handle null responses in checkout creation
docs: update README with new tool examples
```
## Supported Tools
Current tools that can be extended or improved:
- **Transactions**: Get transaction details, resend webhooks
- **Checkout**: Create payment links, disable links
- **Plans**: Create and retrieve subscription plans
- **Refunds**: Process transaction refunds
- **Subscriptions**: Manage customer subscriptions
## Common Issues and Solutions
### TypeScript Errors
- Ensure all types are properly imported
- Use `as const` for literal types in MCP responses
- Check that Zod schemas match the expected API parameters
### MCP Integration Issues
- Verify tool schemas use `.shape` property for registration
- Ensure return objects match MCP content format
- Check that all async functions properly handle errors
### API Client Issues
- Verify OpenAPI specifications are accurate
- Regenerate types after spec changes: `npm run build:types`
- Check HTTP client configuration in `src/client/http/`
## Submitting Changes
1. **Create a feature branch**
```bash
git checkout -b feature/your-feature-name
```
2. **Make your changes** following the guidelines above
3. **Test your changes**
```bash
npm run build
npm test # if tests are available
```
4. **Commit your changes**
```bash
git add .
git commit -m "feat: describe your changes"
```
5. **Push and create a pull request**
```bash
git push origin feature/your-feature-name
```
6. **Fill out the PR template** with:
- Description of changes
- Testing performed
- Any breaking changes
- Screenshots if applicable
## Code Review Process
- All contributions require review
- Address feedback promptly
- Ensure CI checks pass
- Maintain backward compatibility when possible
## Getting Help
- Open an issue for bugs or feature requests
- Join discussions in existing issues
- Check the [MCP documentation](https://modelcontextprotocol.io) for protocol details
- Review [Flutterwave API docs](https://developer.flutterwave.com) for API details
## License
By contributing, you agree that your contributions will be licensed under the same license as the project.
```
--------------------------------------------------------------------------------
/src/client/schema.ts:
--------------------------------------------------------------------------------
```typescript
```
--------------------------------------------------------------------------------
/src/types/checkout/index.ts:
--------------------------------------------------------------------------------
```typescript
export * from "./schema.js";
```
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
```json
{
"recommendations": [
"github.vscode-github-actions"
]
}
```
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
```json
{
"IDX.aI.enableInlineCompletion": true,
"IDX.aI.enableCodebaseIndexing": true
}
```
--------------------------------------------------------------------------------
/src/prompts/index.ts:
--------------------------------------------------------------------------------
```typescript
import { registerTransactionsPrompts } from './transactions.js';
export function registerPrompts() {
registerTransactionsPrompts();
}
```
--------------------------------------------------------------------------------
/src/types/transaction/schema.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from 'zod';
export const TransactionSchema = {
tx_id: z.string().min(1, 'Transaction ID is required').describe('Transaction ID'),
}
```
--------------------------------------------------------------------------------
/src/client/middleware/authMiddlewareV3.ts:
--------------------------------------------------------------------------------
```typescript
import { Middleware } from "openapi-fetch";
export const authMiddlewareV3: Middleware = {
async onRequest({ request }) {
request.headers.set("Authorization", "Bearer " + process.env.FLW_SECRET_KEY);
return request;
}
};
export default authMiddlewareV3;
```
--------------------------------------------------------------------------------
/src/client/index.ts:
--------------------------------------------------------------------------------
```typescript
import transactions from "./lib/transactions.js"
import checkout from "./lib/checkout.js";
import plans from "./lib/plan.js";
export default class Flutterwave {
static transactions() {
return transactions;
}
static checkout() {
return checkout;
}
static plans() {
return new plans;
}
}
```
--------------------------------------------------------------------------------
/src/tools/index.ts:
--------------------------------------------------------------------------------
```typescript
import {registerCheckoutTools} from './checkout.js';
import { registerTransactionTools } from './transaction.js';
import { registerRequiredTools } from './required.js';
import { registerPlanTools } from './plan.js';
export function registerTools() {
registerRequiredTools();
registerTransactionTools();
registerCheckoutTools();
registerPlanTools();
}
```
--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { registerTools } from "./tools/index.js";
import { registerPrompts } from "./prompts/index.js";
// Create server instance.
export const server = new McpServer({
name: "flutterwave",
version: "1.2.2",
});
// Register tools with the server.
registerTools();
registerPrompts();
export default server;
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
}
```
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
```typescript
export type Options = {
tools?: string[];
apiKey?: string;
};
export type CheckoutPayload = {
tx_ref: string,
amount: string,
currency: string,
redirect_url: string,
customer: {
email: string,
name: string,
phonenumber: string,
},
customizations: {
title: string,
},
configurations: {
session_duration: number,
max_retry_attempt: number
},
}
```
--------------------------------------------------------------------------------
/src/client/client.ts:
--------------------------------------------------------------------------------
```typescript
import createClient, { Middleware } from "openapi-fetch";
import type { paths } from "./types/v3.js";
import authMiddlewareV3 from "./middleware/authMiddlewareV3.js";
const FLW_API_VERSION = process.env.FLW_VERSION || 'v3';
const FLW_API_BASE = "https://api.flutterwave.com/" + FLW_API_VERSION;
const USER_AGENT = "flutterwave-mcp/0.1.0";
const client = createClient<paths>({ baseUrl: FLW_API_BASE, headers: { "User-Agent": USER_AGENT } });
client.use(authMiddlewareV3);
export default client
```
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
FROM node:20.19.5-alpine3.22 AS builder
WORKDIR /app
ENV DOCKER=true
# Copy package files and install dependencies
COPY package*.json ./
RUN npm ci
# Copy source code
COPY tsconfig.json ./
COPY src/ ./src/
# Build the application
RUN npm run build
# Start a new stage for a smaller production image
FROM node:20.19.5-alpine3.22
WORKDIR /app
# Set environment variables
ENV DOCKER=true
ENV NODE_ENV=production
ENV FLW_SECRET_KEY=${FLW_SECRET_KEY}
# Copy package files and install production dependencies only
COPY package*.json ./
RUN npm ci --omit=dev
# Copy the built application from the builder stage
COPY --from=builder /app/build ./build
# Run the application
CMD ["node", "build/index.js"]
```
--------------------------------------------------------------------------------
/src/types/plan/schema.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from 'zod';
export const CreatePlanPayloadSchema = {
name: z.string().min(1, "Name is required"),
amount: z.number().positive("Amount must be a positive number"),
interval: z.enum(['daily', 'weekly', 'monthly', 'yearly']).refine(val => ['daily', 'weekly', 'monthly', 'yearly'].includes(val), { message: "Interval must be one of 'daily', 'weekly', 'monthly', 'yearly'" }),
duration: z.number().int().positive("Duration must be a positive integer"),
};
export const GetPlansFiltersSchema = {
name: z.string().min(1).optional(),
amount: z.number().positive().optional(),
interval: z.enum(['daily', 'weekly', 'monthly', 'yearly']).optional(),
status: z.enum(['active', 'inactive']).optional(),
from: z.string().optional(),
to: z.string().optional(),
};
```
--------------------------------------------------------------------------------
/server.json:
--------------------------------------------------------------------------------
```json
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
"name": "io.github.bajoski34/mcp-flutterwave",
"description": "MCP Server to interact with Flutterwave APIs.",
"repository": {
"url": "https://github.com/bajoski34/mcp-flutterwave",
"source": "github"
},
"version": "1.2.2",
"packages": [
{
"registryType": "npm",
"registryBaseUrl": "https://registry.npmjs.org",
"identifier": "mcp-flutterwave",
"version": "1.2.2",
"transport": {
"type": "stdio"
},
"environmentVariables": [
{
"description": "Your SECRET API key for the service",
"isRequired": true,
"format": "string",
"isSecret": true,
"name": "FLW_SECRET_KEY"
}
]
}
]
}
```
--------------------------------------------------------------------------------
/src/config/index.ts:
--------------------------------------------------------------------------------
```typescript
import { version } from 'os';
import {z} from 'zod';
// environment variable schema for validation
const envSchema = z.object({
FLW_SECRET_KEY: z.string().min(1, 'Flutterwave Secret Key is required'),
NODE_ENV: z
.enum(['development', 'production', 'test'])
.optional()
.default('development'),
});
// Parse and validate environment variables
const envParse = envSchema.safeParse(process.env);
if (!envParse.success) {
console.error('❌ Invalid environment variables:', envParse.error.format());
throw new Error('Invalid environment variables');
}
// Export validated config
export const config = {
flutterwave: {
secretKey: envParse.data.FLW_SECRET_KEY,
apiUrl: 'https://api.flutterwave.com',
version: 'v3',
},
server: {
environment: envParse.data.NODE_ENV,
},
} as const;
```
--------------------------------------------------------------------------------
/src/tools/required.ts:
--------------------------------------------------------------------------------
```typescript
import { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js";
import { type Tool } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { server } from "../server.js";
const tools:any[] = [];
/**
* Register tool for the Flutterwave MCP Server to function
*/
// tools.push({
// name: "sample",
// description: "Sample Tool",
// inputSchema: { sample: z.string().min(1, "Sample is required").describe("Sample") },
// cb: ((args: any) => {
// return {
// content: [{ type: "text", text: `Sample Tool Executed with args: ${JSON.stringify(args)}` }] };
// }),
// });
export async function registerRequiredTools() {
// Register required tools with the server.
for (const tool of tools) {
server.tool(tool.name, tool.description, tool.inputSchema, tool.cb);
}
}
```
--------------------------------------------------------------------------------
/src/types/checkout/schema.ts:
--------------------------------------------------------------------------------
```typescript
import { z } from 'zod';
export const CheckoutPayloadSchema = {
tx_ref: z.string().min(1, "Transaction reference is required"),
amount: z.string().min(1, "Amount is required"),
currency: z.string().min(1, "Currency is required"),
redirect_url: z.string().url("Redirect URL must be a valid URL"),
customer: z.object({
email: z.string().email("Invalid email address"),
name: z.string().min(1, "Customer name is required"),
phonenumber: z.string().min(1, "Customer phone number is required"),
}),
customizations: z.object({
title: z.string().min(1, "Title is required"),
}),
configurations: z.object({
session_duration: z.number().int().positive("Session duration must be a positive integer"),
max_retry_attempt: z.number().int().nonnegative("Max retry attempt must be a non-negative integer")
}),
};
export const DisableCheckoutSchema = {
link: z.string().url("Checkout link must be a valid URL"),
};
```
--------------------------------------------------------------------------------
/src/client/http/index.ts:
--------------------------------------------------------------------------------
```typescript
import createClient from "openapi-fetch";
import type { paths as checkoutPaths } from "../types/v3/checkout.js";
import type { paths as transactionPaths } from "../types/v3/transactions.js";
import type { paths as planPaths } from "../types/v3/plans.js";
import authMiddlewareV3 from "../middleware/authMiddlewareV3.js";
import { config } from "../../config/index.js";
const FLW_API_VERSION = process.env.FLW_VERSION || config.flutterwave.version;
const FLW_API_BASE = config.flutterwave.apiUrl + '/' + FLW_API_VERSION;
const USER_AGENT = "flutterwave-mcp/0.1.0";
const transactionClient = createClient<transactionPaths>({ baseUrl: FLW_API_BASE, headers: { "User-Agent": USER_AGENT } });
transactionClient.use(authMiddlewareV3);
const checkoutClient = createClient<checkoutPaths>({ baseUrl: FLW_API_BASE, headers: { "User-Agent": USER_AGENT } });
checkoutClient.use(authMiddlewareV3);
const planClient = createClient<planPaths>({ baseUrl: FLW_API_BASE, headers: { "User-Agent": USER_AGENT } });
planClient.use(authMiddlewareV3);
export {
transactionClient,
checkoutClient,
planClient
}
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "mcp-flutterwave",
"type": "module",
"bin": {
"mcp-flutterwave": "build/index.js"
},
"version": "1.2.2",
"mcpName": "io.github.bajoski34/mcp-flutterwave",
"repository": {
"type": "git",
"url": "https://github.com/bajoski34/mcp-flutterwave.git"
},
"description": "MCP Server to interact with Flutterwave APIs.",
"main": "build/index.js",
"scripts": {
"build": "npm run build:types &&tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
"clean": "rm -rf build",
"build:types": "./bin/generate-openapi-typescript"
},
"files": [
"build"
],
"keywords": [
"mcp",
"model-context-protocol",
"flutterwave",
"payment",
"fintech",
"ai"
],
"author": "Abraham Olaobaju <[email protected]>",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.18.2",
"colors": "^1.4.0",
"flutterwave-node-v3": "^1.1.15",
"openapi-fetch": "^0.14.0",
"ts-node": "^10.9.2",
"zod": "^3.24.2"
},
"devDependencies": {
"@types/node": "^22.13.10",
"nodemon": "^3.1.9",
"openapi-typescript": "^7.6.1",
"typescript": "^5.8.2",
"zod-to-json-schema": "^3.24.6"
}
}
```
--------------------------------------------------------------------------------
/src/client/lib/plan.ts:
--------------------------------------------------------------------------------
```typescript
import { planClient as client } from "../http/index.js";
import type { paths } from "../types/v3/plans.js";
type CreatePlanPayload = (
paths["/plans"]["post"]["requestBody"]
& { content: { "application/json": unknown } }
)["content"]["application/json"];
type CreatePlanResponse = paths["/plans"]["post"]["responses"]["200"]["content"]["application/json"];
type GetPlanResponse = paths["/plans"]["get"]["responses"]["200"]["content"]["application/json"];
type GetPlanParams = paths["/plans"]["get"]["parameters"]["query"];
export default class Plan {
async create(payload: CreatePlanPayload): Promise<{ status: number; data: CreatePlanResponse | string | null }> {
try {
const response = await client.POST("/plans", { body: payload });
return {
status: response.response?.status ?? 500,
data: response.data ?? null
};
} catch (error) {
return { status: 500, data: (error as any)?.message || 'An error occurred'};
}
}
async get(params?: GetPlanParams): Promise<{ status: number; data: GetPlanResponse | null }> {
try {
const response = await client.GET("/plans", {
query: params || {
page: 1,
status: "active",
from: "",
to: "",
amount: 0,
interval: ""
}
});
return {
status: response.response?.status ?? 500,
data: response.data ?? null
};
} catch (error) {
return { status: 500, data: null };
}
}
}
```
--------------------------------------------------------------------------------
/src/client/lib/checkout.ts:
--------------------------------------------------------------------------------
```typescript
import { checkoutClient as client } from "../http/index.js";
type CheckoutPayload = {
tx_ref: string,
amount: string,
currency: string,
redirect_url: string,
customer: {
email: string,
name: string,
phonenumber: string,
},
customizations: {
title: string,
},
configurations: {
session_duration: number,
max_retry_attempt: number
},
}
/**
* This checkout create paymrnt.
* https://developer.flutterwave.com/docs/flutterwave-standard-1
*
*/
async function create(payment_data: CheckoutPayload) : Promise<{ data: {
data: any; link: string
}, status: number } | undefined> {
const { data, error } = await client.POST("/payments", {
body: {
...payment_data
}
});
if (error) {
console.error(error);
return;
}
return data;
}
// {
// "status": "success",
// "message": "LINK DISABLED",
// "data": true
// }
/**
* Disable a checkout link.
* https://developer.flutterwave.com/v3.0.0/docs/flutterwave-standard-1#how-to-disable-a-payment-link-via-api
* @param payment_link
* @returns
*/
async function disable(payment_link: string): Promise<{
status: string;
message: string;
data: null;
} | undefined> {
const { data, error } = await client.POST("/payments/link/disable", {
body:{
link: payment_link
}
});
if (error) {
console.error(error);
throw new Error('Failed to disable checkout link', { cause: error });
}
// Ensure returned object always has data: null
return {
status: data?.status || 'error',
message: data?.message || 'An error occurred',
data: null
};
}
export default {
create,
disable_link: disable
}
```
--------------------------------------------------------------------------------
/src/tools/retry_transaction.ts:
--------------------------------------------------------------------------------
```typescript
import Flutterwave from "../client/index.js";
export default async ({ tx_id }: { tx_id: string }) => {
if (!process.env.FLW_SECRET_KEY) {
return {
content: [{ type: "text", text: "API key is missing. Please check configuration." }],
};
}
const transactions = Flutterwave.transactions();
try {
const response = await transactions.retry_transaction(tx_id);
if (!response || response.status === 'error') {
return {
content: [{
type: "text",
text: response?.message || `Unable to retry transaction ${tx_id}`
}],
};
}
if (response.status === 'info' && response.data) {
const data = response.data;
return {
content: [
{
type: "text",
text: `Transaction retry analysis completed for ${tx_id}:\n` +
`Status: ${data.status}\n` +
`Original Reference: ${data.original_tx_ref}\n` +
`Amount: ${data.amount} ${data.currency}\n` +
`Customer: ${data.customer_email}\n\n` +
`${response.message}`
},
],
};
}
return {
content: [
{
type: "text",
text: `Transaction retry completed: ${response.message}`,
},
],
};
} catch (error) {
console.error(`Error retrying transaction ${tx_id}:`, error);
return {
content: [{ type: "text", text: `Error retrying transaction ${tx_id}` }],
};
}
};
```
--------------------------------------------------------------------------------
/src/prompts/transactions.ts:
--------------------------------------------------------------------------------
```typescript
import {server} from '../server.js';
const transactionInsightsPrompt = `
You are a helpful assistant connecting to Flutterwave Server. Your goal is to provide the user with actionable insights into transactions, including revenue, volume, success/failure rates, and trends.
Available Tools:
1. \`list_transactions\`: Fetches detailed transaction records (amount, currency, status, customer, etc.).
2. \`get_transaction_totals\`: Returns aggregated metrics such as total revenue, transaction count, success rate, and failure rate.
3. \`list_customers\`: Provides information about customers to segment transactions and identify top spenders.
Workflow:
1. When a user asks about transaction insights (e.g., "How are my transactions this month?"), call \`get_transaction_totals\` with appropriate date filters.
2. Use \`list_transactions\` for deeper analysis like top payment methods, currencies, or customer segments.
3. Highlight key metrics:
- Total revenue
- Number of successful vs failed transactions
- Average transaction value
- Top payment methods and currencies
- Top customers by volume or value
4. Identify trends such as:
- Day with highest sales
- Increase/decrease compared to previous period
- Most common reasons for failed transactions (if available)
5. Present the insights in a concise, structured way (tables, bullet points, percentages).
6. Offer follow-up insights (e.g., "Would you like to see a breakdown by country or payment method?").
7. Focus on turning raw transaction data into clear business insights.
`;
export function registerTransactionsPrompts() {
server.prompt(
'show-transaction-insights',
'Give me insights into my transactions this month',
{},
async () => ({
messages: [
{
role: 'assistant',
content: {
type: 'text',
text: transactionInsightsPrompt,
},
},
],
})
);
}
```
--------------------------------------------------------------------------------
/src/tools/get_transaction_timeline.ts:
--------------------------------------------------------------------------------
```typescript
import Flutterwave from "../client/index.js";
export default async ({ tx_id }: { tx_id: string }) => {
if (!process.env.FLW_SECRET_KEY) {
return {
content: [{ type: "text", text: "API key is missing. Please check configuration." }],
};
}
const transactions = Flutterwave.transactions();
try {
const { status, data } = await transactions.timeline(tx_id) || { status: null, data: null };
if(typeof status == 'number' && status >= 400) {
return {
content: [{ type: "text", text: `Unable to retrieve timeline for ${tx_id}` }],
};
}
if(!data) {
return {
content: [{ type: "text", text: `Unable to retrieve timeline for ${tx_id}` }],
};
}
if(!(data as any)?.status) {
return {
content: [{ type: "text", text: `Unable to retrieve timeline for ${tx_id}` }],
};
}
// Format the timeline data for display
let timelineText = `Transaction Timeline for ${tx_id}:\n\n`;
if ((data as any).data && Array.isArray((data as any).data)) {
(data as any).data.forEach((event: any, index: number) => {
timelineText += `${index + 1}. ${event.event || 'Event'}: ${event.description || 'No description'}\n`;
if (event.created_at) {
timelineText += ` Time: ${event.created_at}\n`;
}
timelineText += '\n';
});
} else {
timelineText += 'No timeline events available for this transaction.';
}
return {
content: [
{
type: "text",
text: timelineText,
},
],
};
} catch (error) {
console.error(`Error fetching timeline for ${tx_id}:`, error);
return {
content: [{ type: "text", text: `Error retrieving timeline for ${tx_id}` }],
};
}
};
```
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
#!/usr/bin/env node
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import server from "./server.js";
import { Options } from "./types/index.js";
import { config } from "./config/index.js";
const ACCEPTED_ARGS = ['tools'];
const ACCEPTED_TOOLS = [
'create_checkout',
'disable_checkout',
'create_refund',
'read_transactions',
'read_transaction',
'read_transaction_timeline',
'resend_transaction_webhook',
'create_plan',
'read_plan',
'read_subscription'
];
export function parseArgs(args: string[]): Options {
const options: Options = {};
args.forEach((arg) => {
if (arg.startsWith('--')) {
const [key, value] = arg.slice(2).split('=');
if (key == 'tools') {
options.tools = value.split(',');
} else {
throw new Error(
`Invalid argument: ${key}. Accepted arguments are: ${ACCEPTED_ARGS.join(
', '
)}`
);
}
}
});
// Check if required tools arguments is present.
if (!options.tools) {
throw new Error('The --tools arguments must be provided.');
}
// Validate tools against accepted enum values.
options.tools.forEach((tool: string) => {
if (tool == 'all') {
return;
}
if (!ACCEPTED_TOOLS.includes(tool.trim())) {
throw new Error(
`Invalid tool: ${tool}. Accepted tools are: ${ACCEPTED_TOOLS.join(
', '
)}`
);
}
});
// Check if API key is either provided in args or set in environment variables
const apiKey = process.env.FLW_SECRET_KEY;
if (!apiKey) {
throw new Error(
'Flutterwave Secret key not provided. Please either pass it as an argument --secret-key=$KEY or set the FLW_SECRET_KEY environment variable.'
);
}
options.apiKey = apiKey;
return options;
}
async function main() {
const options = parseArgs(process.argv.slice(2));
const transport = new StdioServerTransport();
// Handle process termination
process.on('SIGINT', async () => {
console.error('Shutting down Flutterwave MCP Server...');
await server.close();
process.exit(0);
});
process.on('SIGTERM', async () => {
console.error('Shutting down Flutterwave MCP Server...');
await server.close();
process.exit(0);
});
await server.connect(transport);
console.error("Flutterwave MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});
```
--------------------------------------------------------------------------------
/src/tools/plan.ts:
--------------------------------------------------------------------------------
```typescript
import Flutterwave from "../client/index.js";
import { CheckoutPayload } from "../types/index.js";
import { server } from "../server.js";
import { CreatePlanPayloadSchema, GetPlansFiltersSchema } from "../types/plan/schema.js";
export async function createPlan(payload: { name: string; amount: number; interval: string; duration?: number; currency?: string; description?: string; }) {
const plans = Flutterwave.plans();
try {
const { status, data } = await plans.create({
...payload,
duration: payload.duration ?? 0, // Provide a default value if undefined
}) || { status: null, data: null };
if(typeof status == 'number' && status >= 400)
return {
content: [{ type: "text" as const, text: `Unable to create plan ${ payload.name } json: ${ JSON.stringify(data) }` }],
};
if(!data)
return {
content: [{ type: "text" as const, text: `Unable to create plan ${ payload.name } json: {message: "No response from server"}` }],
};
return {
content: [
{
type: "text" as const,
text: `Plan created with ID: ${ (data as { data?: { id?: string } }).data?.id }`,
},
],
};
} catch (error) {
return {
content: [{ type: "text" as const, text: `Error Occured on creating plan ${ payload.name } json: ${ JSON.stringify(error) }` }],
};
}
}
export async function getPlans(filters?: { name?: string; amount?: number; interval?: string; status?: string; from?: string; to?: string; }) {
const plans = Flutterwave.plans();
try {
const { status, data } = await plans.get({
...filters
}) || { status: null, data: null };
if(typeof status == 'number' && status >= 400)
return {
content: [{ type: "text" as const, text: `Unable to retrieve plans` }],
};
if(!data)
return {
content: [{ type: "text" as const, text: `Unable to retrieve plans` }],
};
if(!data?.status)
return {
content: [{ type: "text" as const, text: `Error Occured on retrieving plans json: ${ JSON.stringify(data) }` }],
};
return {
content: [
{
type: "text" as const,
text: `Plans retrieved: ${ JSON.stringify(data.data) }`,
},
],
};
} catch (error) {
return {
content: [{ type: "text" as const, text: `Error Occured on retrieving plans json: ${ JSON.stringify(error) }` }],
};
}
}
export async function registerPlanTools() {
server.tool(
"create_payment_plan",
"Create a payment plan with Flutterwave.",
CreatePlanPayloadSchema,
async (input) => await createPlan(input)
)
server.tool(
"get_payment_plans",
"Get payment plans with optional filters",
GetPlansFiltersSchema,
async (input) => await getPlans(input)
)
}
```
--------------------------------------------------------------------------------
/src/tools/checkout.ts:
--------------------------------------------------------------------------------
```typescript
import Flutterwave from "../client/index.js";
import { CheckoutPayload } from "../types/index.js";
import { server } from "../server.js";
import { CheckoutPayloadSchema, DisableCheckoutSchema } from "../types/checkout/index.js";
export async function createCheckout(payload: CheckoutPayload) {
const transactions = Flutterwave.checkout();
try {
const { status, data } = await transactions.create(payload) || { status: null, data: null };
if(typeof status == 'number' && status >= 400)
return {
content: [{ type: "text" as const, text: `Unable to create a checkout url for ${ payload.customer.name }` }],
};
if(!data)
return {
content: [{ type: "text" as const, text: `Unable to create a checkout url for ${ payload.customer.name }` }],
};
if(!data?.data?.status)
return {
content: [{ type: "text" as const, text: `Error Occured on creating checkout url for ${ payload.customer.name } json: ${ JSON.stringify(data) }` }],
};
return {
content: [
{
type: "text" as const,
text: `Checkout link at: ${ data.data?.link }`,
},
],
};
} catch (error) {
return {
content: [{ type: "text" as const, text: `Error Occured on creating checkout url for ${ payload.customer.name } json: ${ JSON.stringify(error) }` }],
};
}
}
export async function disableCheckout(link: string) {
const transactions = Flutterwave.checkout();
try {
const { status, data } = await transactions.disable_link(link) || { status: null, data: null };
if(typeof status == 'number' && status >= 400)
return {
content: [{ type: "text" as const, text: `Unable to disable checkout link ${ link } json: ${ JSON.stringify(data) }` }],
};
if(!data)
return {
content: [{ type: "text" as const, text: `Unable to disable checkout link ${ link }` }],
};
return {
content: [
{
type: "text" as const,
text: `Successfully disabled the link.`,
},
],
};
} catch (error) {
return {
content: [{ type: "text" as const, text: `Error Occured on diabling the checkout: ${ link } json: ${ JSON.stringify(error) }` }],
};
}
}
export function registerCheckoutTools() {
server.tool(
"create_checkout",
"Create a checkout link with Flutterwave.",
CheckoutPayloadSchema,
async (args) => {
try {
return await createCheckout(args);
} catch (error) {
return {
content: [{ type: "text" as const, text: `Error Occured on creating checkout url for ${ args.customer.name }` }],
};
}
}
);
server.tool(
"disable_checkout",
"Disable a checkout link on Flutterwave.",
DisableCheckoutSchema,
async (args) => {
return await disableCheckout(args.link);
}
);
}
```
--------------------------------------------------------------------------------
/src/client/specs/v3/checkout.yaml:
--------------------------------------------------------------------------------
```yaml
openapi: 3.0.3
info:
title: Flutterwave Transactions API
description: API for managing and retrieving transaction details via Flutterwave.
version: 1.0.0
servers:
- url: https://api.flutterwave.com/v3
paths:
/payments:
post:
summary: Process a payment through Flutterwave
description: Initiates a payment process through Flutterwave using a unique transaction reference.
operationId: createPayment
requestBody:
description: Payment data for the transaction
content:
application/json:
schema:
type: object
properties:
tx_ref:
type: string
example: 'txnref_djsdkjsnkdjvnsdfj'
amount:
type: string
example: '7500'
currency:
type: string
example: 'NGN'
redirect_url:
type: string
example: 'https://example_company.com/success'
customer:
type: object
properties:
email:
type: string
example: '[email protected]'
name:
type: string
example: 'Flutterwave Developers'
phonenumber:
type: string
example: '09012345678'
customizations:
type: object
properties:
title:
type: string
example: 'Flutterwave Standard Payment'
required:
- tx_ref
- amount
- currency
- redirect_url
- customer
- customizations
/payments/link/disable:
post:
summary: Disable a Flutterwave payment link
description: Disables a specific payment link for the given URL.
operationId: disablePaymentLink
requestBody:
description: Payment link data to disable
content:
application/json:
schema:
type: object
properties:
link:
type: string
example: 'https://checkout.flutterwave.com/v3/hosted/pay/flwlnk-01j8hkejppgm821xv8mfxfpgrb'
required:
- link
responses:
'200':
description: Payment link disabled successfully
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: 'success'
message:
type: string
example: 'Payment link has been disabled successfully'
'400':
description: Bad request, invalid data
'401':
description: Unauthorized, invalid API key
'404':
description: Payment link not found
'500':
description: Internal server error
components:
schemas:
Transaction:
type: object
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
```
--------------------------------------------------------------------------------
/src/client/lib/transactions.ts:
--------------------------------------------------------------------------------
```typescript
import { transactionClient as client } from "../http/index.js";
/**
* This endpoint helps you query the details of a transaction.
* https://developer.flutterwave.com/reference/verify-transaction.
* @param tx_id
* @returns
*/
async function get(tx_id: string) {
const { data, error } = await client.GET("/transactions/{id}/verify", {
params: {
path: { id: tx_id },
},
});
if (error) {
console.error(error);
return;
}
return data;
}
/**
* This endpoint helps you query the details of a transaction using the transaction reference.
* https://developer.flutterwave.com/reference/verify-transaction-with-tx_ref
* @param tx_ref
* @returns
*/
async function get_with_reference(tx_ref: string) {
const { data, error } = await client.GET("/transactions/verify_by_reference", {
params: {
query: { tx_ref },
},
});
if (error) {
console.error(error);
return;
}
return data;
}
/**
* This endpoint helps you resend webhooks from failed sending queues to your server.
* https://developer.flutterwave.com/reference/resend-transaction-webhook
*/
async function send_failed_webhook(tx_id: string) {
const { data, error } = await client.POST("/transactions/{id}/resend-hook", {
params: {
path: { id: tx_id },
},
});
if (error) {
console.error(error);
return;
}
return data;
}
/**
* Review the timeline for a transaction from initiation to completion.
* https://developer.flutterwave.com/reference/get-transaction-events
*/
async function timeline(tx_id: string) {
const { data, error } = await client.POST("/transactions/{id}/events", {
params: {
path: { id: tx_id },
},
});
if (error) {
console.error(error);
return;
}
return data;
}
/**
* Retry a failed transaction by creating a new transaction with the same details
* This is a wrapper function that gets the original transaction and recreates it
*/
async function retry_transaction(tx_id: string) {
try {
// First get the original transaction details
const original = await get(tx_id);
if (!original || !original.data) {
return {
status: 'error',
message: 'Could not retrieve original transaction details',
data: null
};
}
const txData = original.data;
// Check if transaction is in a retriable state
if (txData.status === 'successful') {
return {
status: 'error',
message: 'Transaction is already successful, cannot retry',
data: null
};
}
return {
status: 'info',
message: 'Transaction retry initiated. Please create a new transaction with the same details.',
data: {
original_tx_ref: txData.tx_ref,
amount: txData.amount,
currency: txData.currency,
customer_email: (txData as any).customer?.email,
status: txData.status
}
};
} catch (error) {
console.error('Error retrying transaction:', error);
return {
status: 'error',
message: 'Failed to retry transaction',
data: null
};
}
}
export default {
get,
get_with_reference,
timeline,
send_failed_webhook,
retry_transaction
}
```
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
```yaml
name: Publish Package
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Version to publish'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test --if-present
- name: Build project
run: npm run build
- name: Configure Git
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
- name: Bump version (manual trigger)
if: github.event_name == 'workflow_dispatch'
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
# Update server.json version to match package.json
VERSION=$(node -p "require('./package.json').version")
jq --arg v "$VERSION" '.version = $v' server.json > tmp && mv tmp server.json
git add package.json package-lock.json server.json
git commit -m "chore: bump version to $VERSION"
git push
- name: Create tag (manual trigger)
if: github.event_name == 'workflow_dispatch'
run: |
VERSION=$(node -p "require('./package.json').version")
git tag "v$VERSION"
git push origin "v$VERSION"
- name: Update server.json version on release
if: github.event_name == 'release'
run: |
VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/tags\/v//')
jq --arg v "$VERSION" '.version = $v' server.json > tmp && mv tmp server.json
jq --arg v "$VERSION" '.packages[0].version = $v' server.json > tmp && mv tmp server.json
- name: Publish to npm
run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create GitHub Release (manual trigger)
if: github.event_name == 'workflow_dispatch'
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ steps.version.outputs.version }}
release_name: Release v${{ steps.version.outputs.version }}
body: |
Release notes for version ${{ steps.version.outputs.version }}
## Changes
- Updated MCP Flutterwave integration
## Installation
```bash
npm install -g mcp-flutterwave
```
## Usage with Claude Desktop
```json
{
"mcpServers": {
"flutterwave": {
"command": "mcp-flutterwave",
"env": {
"FLW_SECRET_KEY": "YOUR_SECRET_KEY"
}
}
}
}
```
draft: false
prerelease: false
- name: Install MCP Publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.0.0/mcp-publisher_1.0.0_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
- name: Login to MCP Registry
run: ./mcp-publisher login github-oidc
- name: Publish to MCP Registry
run: ./mcp-publisher publish
```
--------------------------------------------------------------------------------
/src/tools/transaction.ts:
--------------------------------------------------------------------------------
```typescript
import Flutterwave from "../client/index.js";
import { server } from "../server.js";
import { TransactionSchema } from "../types/transaction/schema.js";
export async function getTransaction({ tx_id }: { tx_id: string }) {
const transactions = Flutterwave.transactions();
try {
const { status, data } = await transactions.get(tx_id) || { status: null, data: null };
if(typeof status == 'number' && status >= 400)
return {
content: [{ type: "text" as const, text: `Unable to retrive ${tx_id}` }],
};
if(!data)
return {
content: [{ type: "text" as const, text: `Unable to retrive ${tx_id}` }],
};
if(!data.status)
return {
content: [{ type: "text" as const, text: `Unable to retrive ${tx_id}` }],
};
return {
content: [
{
type: "text" as const,
text: `Transaction Status: ${data.status}\nAmount: ${data.amount}\nCurrency: ${data.currency}`,
},
],
};
} catch (error) {
return {
content: [{ type: "text" as const, text: `Unable to retrive ${tx_id}` }],
};
}
}
export async function getTransactionTimeline({ tx_id }: { tx_id: string }) {
const transactions = Flutterwave.transactions();
try {
const { status, data } = await transactions.timeline(tx_id) || { status: null, data: null };
if(typeof status == 'number' && status >= 400)
return {
content: [{ type: "text" as const, text: `Unable to retrive timeline for ${tx_id}` }],
};
if(!data)
return {
content: [{ type: "text" as const, text: `Unable to retrive timeline for ${tx_id}` }],
};
return {
content: [
{
type: "text" as const,
text: `Transaction Timeline: ${JSON.stringify(data)}`,
},
],
};
} catch (error) {
return {
content: [{ type: "text" as const, text: `Unable to retrive timeline for ${tx_id}` }],
};
}
}
export async function resendFailedWebhook({ tx_id }: { tx_id: string }) {
const transactions = Flutterwave.transactions();
try {
const response = await transactions.send_failed_webhook(tx_id);
const { status, data } = response || { status: 200, data: { status: "successful" }};
if (!data || !data.status) {
return {
content: [{ type: "text" as const, text: `Unable to retrieve ${tx_id}` }],
};
}
if (typeof status === "number" && status >= 400) {
return {
content: [{ type: "text" as const, text: `Unable to retrieve ${tx_id}` }],
};
}
return {
content: [
{
type: "text" as const,
text: `webhook Sent`,
},
],
};
} catch (error) {
console.error(`Error fetching transaction ${tx_id}:`, error);
return {
content: [{ type: "text" as const, text: `Error retrieving ${tx_id}` }],
};
}
};
export async function registerTransactionTools() {
server.tool(
"read_transaction",
"Get Transaction Details",
TransactionSchema,
async (args) => {
return await getTransaction(args);
}
);
server.tool(
"read_transaction_timeline",
"Get Transaction Timeline",
TransactionSchema,
async (args) => {
return await getTransactionTimeline(args);
}
);
server.tool(
"resend_transaction_webhook",
"Resend Failed Webhook",
TransactionSchema,
async (args) => {
return await resendFailedWebhook(args);
}
);
}
```
--------------------------------------------------------------------------------
/src/client/types/v3/checkout.d.ts:
--------------------------------------------------------------------------------
```typescript
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/payments": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Process a payment through Flutterwave
* @description Initiates a payment process through Flutterwave using a unique transaction reference.
*/
post: operations["createPayment"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/payments/link/disable": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Disable a Flutterwave payment link
* @description Disables a specific payment link for the given URL.
*/
post: operations["disablePaymentLink"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
Transaction: Record<string, never>;
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
createPayment: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** @description Payment data for the transaction */
requestBody?: {
content: {
"application/json": {
/** @example txnref_djsdkjsnkdjvnsdfj */
tx_ref: string;
/** @example 7500 */
amount: string;
/** @example NGN */
currency: string;
/** @example https://example_company.com/success */
redirect_url: string;
customer: {
/** @example [email protected] */
email?: string;
/** @example Flutterwave Developers */
name?: string;
/** @example 09012345678 */
phonenumber?: string;
};
customizations: {
/** @example Flutterwave Standard Payment */
title?: string;
};
};
};
};
responses: never;
};
disablePaymentLink: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** @description Payment link data to disable */
requestBody?: {
content: {
"application/json": {
/** @example https://checkout.flutterwave.com/v3/hosted/pay/flwlnk-01j8hkejppgm821xv8mfxfpgrb */
link: string;
};
};
};
responses: {
/** @description Payment link disabled successfully */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example success */
status?: string;
/** @example Payment link has been disabled successfully */
message?: string;
};
};
};
/** @description Bad request, invalid data */
400: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Unauthorized, invalid API key */
401: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Payment link not found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Internal server error */
500: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
}
```
--------------------------------------------------------------------------------
/src/client/types/v3/plans.d.ts:
--------------------------------------------------------------------------------
```typescript
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/plans": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Retrieve all subscription plans
* @description Fetch a list of all subscription plans.
*/
get: operations["getPlans"];
put?: never;
/**
* Create a new subscription plan
* @description Create a new subscription plan with specified details.
*/
post: operations["createPlan"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: never;
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
getPlans: {
parameters: {
query?: {
/** @description Page number for pagination */
page?: number;
/** @description This is the exact amount set when creating the payment plan */
amount?: number;
/** @description This is the currency used for the payment plan */
currency?: string;
/** @description This is the status of the payment plan */
status?: string;
/** @description This is the interval of the payment plan */
interval?: string;
/** @description This is the start date for the payment plan */
from?: string;
/** @description This is the end date for the payment plan */
to?: string;
};
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description A list of subscription plans */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example success */
status?: string;
/** @example Payment plans fetched */
message?: string;
meta?: {
page_info?: {
/** @example 10 */
current_page?: number;
/** @example 1 */
total_pages?: number;
};
};
data?: {
/** @example pln_123456789 */
id?: string;
/** @example Premium Plan */
name?: string;
/** @example 5000 */
amount?: number;
/** @example monthly */
interval?: string;
/** @example 12 */
duration?: number;
/** @example NGN */
currency?: string;
/** @example active */
status?: string;
/**
* Format: date-time
* @example 2023-01-01T00:00:00Z
*/
created_at?: string;
}[];
};
};
};
};
};
createPlan: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** @description Plan data for the new subscription plan */
requestBody?: {
content: {
"application/json": {
/** @example Premium Plan */
name: string;
/** @example 5000 */
amount: number;
/** @example monthly */
interval: string;
/** @example 12 */
duration: number;
/** @example NGN */
currency?: string;
};
};
};
responses: {
/** @description Subscription plan created successfully */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example success */
status?: string;
/** @example Payment plan created */
message?: string;
data?: {
/** @example pln_123456789 */
id?: string;
/** @example Premium Plan */
name?: string;
/** @example 5000 */
amount?: number;
/** @example monthly */
interval?: string;
/** @example 12 */
duration?: number;
/** @example NGN */
currency?: string;
/** @example active */
status?: string;
/** @example pln_tok_abcdef123456 */
plan_token?: string;
/**
* Format: date-time
* @example 2023-01-01T00:00:00Z
*/
created_at?: string;
};
};
};
};
};
};
}
```
--------------------------------------------------------------------------------
/src/client/specs/v3/plan.yaml:
--------------------------------------------------------------------------------
```yaml
openapi: 3.0.3
info:
title: Flutterwave Transactions API
description: API for managing and retrieving transaction details via Flutterwave.
version: 1.0.0
servers:
- url: https://api.flutterwave.com/v3
paths:
/plans:
post:
summary: Create a new subscription plan
description: Create a new subscription plan with specified details.
operationId: createPlan
requestBody:
description: Plan data for the new subscription plan
content:
application/json:
schema:
type: object
properties:
name:
type: string
example: 'Premium Plan'
amount:
type: integer
example: 5000
interval:
type: string
example: 'monthly'
duration:
type: integer
example: 12
currency:
type: string
example: 'NGN'
required:
- name
- amount
- interval
- duration
responses:
'200':
description: Subscription plan created successfully
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: 'success'
message:
type: string
example: 'Payment plan created'
data:
type: object
properties:
id:
type: string
example: 'pln_123456789'
name:
type: string
example: 'Premium Plan'
amount:
type: integer
example: 5000
interval:
type: string
example: 'monthly'
duration:
type: integer
example: 12
currency:
type: string
example: 'NGN'
status:
type: string
example: 'active'
plan_token:
type: string
example: 'pln_tok_abcdef123456'
created_at:
type: string
format: date-time
example: '2023-01-01T00:00:00Z'
get:
summary: Retrieve all subscription plans
description: Fetch a list of all subscription plans.
operationId: getPlans
parameters:
- in: query
name: page
schema:
type: integer
example: 1
description: Page number for pagination
- in: query
name: amount
schema:
type: integer
example: 10
description: This is the exact amount set when creating the payment plan
- in: query
name: currency
schema:
type: string
example: 'NGN'
description: This is the currency used for the payment plan
- in: query
name: status
schema:
type: string
example: 'active'
description: This is the status of the payment plan
- in: query
name: interval
schema:
type: string
example: 'monthly'
description: This is the interval of the payment plan
- in: query
name: from
schema:
type: string
example: '2023-01-01'
description: This is the start date for the payment plan
- in: query
name: to
schema:
type: string
example: '2023-12-31'
description: This is the end date for the payment plan
responses:
'200':
description: A list of subscription plans
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: 'success'
message:
type: string
example: 'Payment plans fetched'
meta:
type: object
properties:
page_info:
type: object
properties:
current_page:
type: integer
example: 10
total_pages:
type: integer
example: 1
data:
type: array
items:
type: object
properties:
id:
type: string
example: 'pln_123456789'
name:
type: string
example: 'Premium Plan'
amount:
type: integer
example: 5000
interval:
type: string
example: 'monthly'
duration:
type: integer
example: 12
currency:
type: string
example: 'NGN'
status:
type: string
example: 'active'
created_at:
type: string
format: date-time
example: '2023-01-01T00:00:00Z'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
```
--------------------------------------------------------------------------------
/src/client/specs/v3/transactions.yaml:
--------------------------------------------------------------------------------
```yaml
openapi: 3.0.3
info:
title: Flutterwave Transactions API
description: API for managing and retrieving transaction details via Flutterwave.
version: 1.0.0
servers:
- url: https://api.flutterwave.com/v3
paths:
/payments:
post:
summary: Process a payment through Flutterwave
description: Initiates a payment process through Flutterwave using a unique transaction reference.
operationId: createPayment
requestBody:
description: Payment data for the transaction
content:
application/json:
schema:
type: object
properties:
tx_ref:
type: string
example: 'txnref_djsdkjsnkdjvnsdfj'
amount:
type: string
example: '7500'
currency:
type: string
example: 'NGN'
redirect_url:
type: string
example: 'https://example_company.com/success'
customer:
type: object
properties:
email:
type: string
example: '[email protected]'
name:
type: string
example: 'Flutterwave Developers'
phonenumber:
type: string
example: '09012345678'
customizations:
type: object
properties:
title:
type: string
example: 'Flutterwave Standard Payment'
required:
- tx_ref
- amount
- currency
- redirect_url
- customer
- customizations
/transactions/{id}/verify:
get:
summary: Retrieve transaction details
description: Fetch the final status of a transaction using its transaction ID.
parameters:
- name: id
in: path
required: true
schema:
type: string
description: The unique transaction ID.
responses:
"200":
description: Successfully retrieved transaction details.
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: success
message:
type: string
example: Transaction fetched successfully
data:
type: object
properties:
id:
type: integer
example: 4975363
tx_ref:
type: string
example: "1710840858755-RND_83"
amount:
type: number
format: float
example: 1000
currency:
type: string
example: NGN
status:
type: string
example: successful
created_at:
type: string
format: date-time
example: "2024-03-19T09:34:27.000Z"
"400":
description: Bad request, invalid transaction ID.
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: error
message:
type: string
example: "Invalid Transaction ID"
data:
type: object
nullable: true
"404":
description: Transaction not found.
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: error
message:
type: string
example: "Transaction not found"
data:
type: object
nullable: true
/transactions/verify_by_reference:
get:
summary: Retrieve transaction details
description: Fetch the final status of a transaction using its transaction ID.
parameters:
- name: tx_ref
in: query
required: true
schema:
type: string
description: The unique transaction ID.
responses:
"200":
description: Successfully retrieved transaction details.
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: success
message:
type: string
example: Transaction fetched successfully
data:
type: object
properties:
id:
type: integer
example: 4975363
tx_ref:
type: string
example: "1710840858755-RND_83"
amount:
type: number
format: float
example: 1000
currency:
type: string
example: NGN
status:
type: string
example: successful
created_at:
type: string
format: date-time
example: "2024-03-19T09:34:27.000Z"
"400":
description: Bad request, invalid transaction ID.
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: error
message:
type: string
example: "Invalid Transaction ID"
data:
type: object
nullable: true
"404":
description: Transaction not found.
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: error
message:
type: string
example: "Transaction not found"
data:
type: object
nullable: true
/transactions/{id}/resend-hook:
post:
summary: Resend failed webhook
description: Resend failed webhook
parameters:
- name: id
in: path
required: true
schema:
type: string
description: The unique transaction ID.
/transactions/{id}/events:
post:
summary: Resend failed webhook.
description: Resend failed webhook.
parameters:
- name: id
in: path
required: true
schema:
type: string
description: The unique transaction ID.
security:
- bearerAuth: []
components:
schemas:
Transaction:
type: object
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
```
--------------------------------------------------------------------------------
/src/client/types/v3.d.ts:
--------------------------------------------------------------------------------
```typescript
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/payments": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Process a payment through Flutterwave
* @description Initiates a payment process through Flutterwave using a unique transaction reference.
*/
post: operations["createPayment"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/transactions/{id}/verify": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Retrieve transaction details
* @description Fetch the final status of a transaction using its transaction ID.
*/
get: {
parameters: {
query?: never;
header?: never;
path: {
/** @description The unique transaction ID. */
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successfully retrieved transaction details. */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example success */
status?: string;
/** @example Transaction fetched successfully */
message?: string;
data?: {
/** @example 4975363 */
id?: number;
/** @example 1710840858755-RND_83 */
tx_ref?: string;
/**
* Format: float
* @example 1000
*/
amount?: number;
/** @example NGN */
currency?: string;
/** @example successful */
status?: string;
/**
* Format: date-time
* @example 2024-03-19T09:34:27.000Z
*/
created_at?: string;
};
};
};
};
/** @description Bad request, invalid transaction ID. */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example error */
status?: string;
/** @example Invalid Transaction ID */
message?: string;
data?: Record<string, never> | null;
};
};
};
/** @description Transaction not found. */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example error */
status?: string;
/** @example Transaction not found */
message?: string;
data?: Record<string, never> | null;
};
};
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/transactions/verify_by_reference": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Retrieve transaction details
* @description Fetch the final status of a transaction using its transaction ID.
*/
get: {
parameters: {
query: {
/** @description The unique transaction ID. */
tx_ref: string;
};
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successfully retrieved transaction details. */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example success */
status?: string;
/** @example Transaction fetched successfully */
message?: string;
data?: {
/** @example 4975363 */
id?: number;
/** @example 1710840858755-RND_83 */
tx_ref?: string;
/**
* Format: float
* @example 1000
*/
amount?: number;
/** @example NGN */
currency?: string;
/** @example successful */
status?: string;
/**
* Format: date-time
* @example 2024-03-19T09:34:27.000Z
*/
created_at?: string;
};
};
};
};
/** @description Bad request, invalid transaction ID. */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example error */
status?: string;
/** @example Invalid Transaction ID */
message?: string;
data?: Record<string, never> | null;
};
};
};
/** @description Transaction not found. */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example error */
status?: string;
/** @example Transaction not found */
message?: string;
data?: Record<string, never> | null;
};
};
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/transactions/{id}/resend-hook": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Resend failed webhook
* @description Resend failed webhook
*/
post: {
parameters: {
query?: never;
header?: never;
path: {
/** @description The unique transaction ID. */
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: never;
};
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/transactions/{id}/events": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Resend failed webhook.
* @description Resend failed webhook.
*/
post: {
parameters: {
query?: never;
header?: never;
path: {
/** @description The unique transaction ID. */
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: never;
};
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
Transaction: Record<string, never>;
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
createPayment: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** @description Payment data for the transaction */
requestBody?: {
content: {
"application/json": {
/** @example txnref_djsdkjsnkdjvnsdfj */
tx_ref: string;
/** @example 7500 */
amount: string;
/** @example NGN */
currency: string;
/** @example https://example_company.com/success */
redirect_url: string;
customer: {
/** @example [email protected] */
email?: string;
/** @example Flutterwave Developers */
name?: string;
/** @example 09012345678 */
phonenumber?: string;
};
customizations: {
/** @example Flutterwave Standard Payment */
title?: string;
};
};
};
};
responses: never;
};
}
```
--------------------------------------------------------------------------------
/src/client/types/v3/transactions.d.ts:
--------------------------------------------------------------------------------
```typescript
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/payments": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Process a payment through Flutterwave
* @description Initiates a payment process through Flutterwave using a unique transaction reference.
*/
post: operations["createPayment"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/transactions/{id}/verify": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Retrieve transaction details
* @description Fetch the final status of a transaction using its transaction ID.
*/
get: {
parameters: {
query?: never;
header?: never;
path: {
/** @description The unique transaction ID. */
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successfully retrieved transaction details. */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example success */
status?: string;
/** @example Transaction fetched successfully */
message?: string;
data?: {
/** @example 4975363 */
id?: number;
/** @example 1710840858755-RND_83 */
tx_ref?: string;
/**
* Format: float
* @example 1000
*/
amount?: number;
/** @example NGN */
currency?: string;
/** @example successful */
status?: string;
/**
* Format: date-time
* @example 2024-03-19T09:34:27.000Z
*/
created_at?: string;
};
};
};
};
/** @description Bad request, invalid transaction ID. */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example error */
status?: string;
/** @example Invalid Transaction ID */
message?: string;
data?: Record<string, never> | null;
};
};
};
/** @description Transaction not found. */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example error */
status?: string;
/** @example Transaction not found */
message?: string;
data?: Record<string, never> | null;
};
};
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/transactions/verify_by_reference": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Retrieve transaction details
* @description Fetch the final status of a transaction using its transaction ID.
*/
get: {
parameters: {
query: {
/** @description The unique transaction ID. */
tx_ref: string;
};
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successfully retrieved transaction details. */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example success */
status?: string;
/** @example Transaction fetched successfully */
message?: string;
data?: {
/** @example 4975363 */
id?: number;
/** @example 1710840858755-RND_83 */
tx_ref?: string;
/**
* Format: float
* @example 1000
*/
amount?: number;
/** @example NGN */
currency?: string;
/** @example successful */
status?: string;
/**
* Format: date-time
* @example 2024-03-19T09:34:27.000Z
*/
created_at?: string;
};
};
};
};
/** @description Bad request, invalid transaction ID. */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example error */
status?: string;
/** @example Invalid Transaction ID */
message?: string;
data?: Record<string, never> | null;
};
};
};
/** @description Transaction not found. */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example error */
status?: string;
/** @example Transaction not found */
message?: string;
data?: Record<string, never> | null;
};
};
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/transactions/{id}/resend-hook": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Resend failed webhook
* @description Resend failed webhook
*/
post: {
parameters: {
query?: never;
header?: never;
path: {
/** @description The unique transaction ID. */
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: never;
};
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/transactions/{id}/events": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Resend failed webhook.
* @description Resend failed webhook.
*/
post: {
parameters: {
query?: never;
header?: never;
path: {
/** @description The unique transaction ID. */
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: never;
};
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
Transaction: Record<string, never>;
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
createPayment: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** @description Payment data for the transaction */
requestBody?: {
content: {
"application/json": {
/** @example txnref_djsdkjsnkdjvnsdfj */
tx_ref: string;
/** @example 7500 */
amount: string;
/** @example NGN */
currency: string;
/** @example https://example_company.com/success */
redirect_url: string;
customer: {
/** @example [email protected] */
email?: string;
/** @example Flutterwave Developers */
name?: string;
/** @example 09012345678 */
phonenumber?: string;
};
customizations: {
/** @example Flutterwave Standard Payment */
title?: string;
};
};
};
};
responses: never;
};
}
```