← All packages

Payments · Convex component

convex-flutterwave

Accept payments and subscriptions with Flutterwave in your Convex app. Reactive transactions, subscription state, and webhook ingestion.

npm install convex-flutterwave
22downloads last week
745downloads last 12 months
v0.0.5latest, Sep 18, 2026
5releases since Sep 12, 2026

Downloads

Download history

Loading download history…

Build this

Build with convex-flutterwave

The install and setup steps from the package documentation.

  1. 1

    Install

    bash
    npm install convex-flutterwave

    Requirements: Convex v1.33.1 or later, Node.js 18+, a account

  2. 2

    Quick Start

    Five steps to add Flutterwave to your Convex app.

    1. Add the component

    In convex/convex.config.ts:

    ts
    import { defineApp } from "convex/server";
    import convexFlutterwave from "convex-flutterwave/convex.config";
    
    const app = defineApp();
    app.use(convexFlutterwave);
    
    export default app;

    2. Set environment variables

    bash
    npx convex env set FLW_SECRET_KEY FLWSECK-xxxxxxxxxxxx
    npx convex env set FLW_WEBHOOK_SECRET_HASH your-chosen-secret-hash

    FLW_WEBHOOK_SECRET_HASH is a random value you choose and enter in the Flutterwave dashboard — it's separate from your API secret key.

    3. Mount the webhook handler

    In convex/http.ts:

    ts
    import { httpRouter } from "convex/server";
    import { components } from "./_generated/api";
    import { Flutterwave } from "convex-flutterwave";
    
    const flutterwave = new Flutterwave(components.convexFlutterwave, {
      secretKey: process.env.FLW_SECRET_KEY!,
      webhookSecretHash: process.env.FLW_WEBHOOK_SECRET_HASH!,
    });
    
    const http = httpRouter();
    
    http.route({
      path: "/webhooks/flutterwave",
      method: "POST",
      handler: flutterwave.webhookHandler,
    });
    
    export default http;

    4. Register the webhook in Flutterwave

    1. In Flutterwave Dashboard → Settings → Webhooks
    2. Set the webhook URL: https://your-deployment.convex.site/webhooks/flutterwave
    3. Set the same secret hash you stored as FLW_WEBHOOK_SECRET_HASH
    4. Save. Flutterwave sends every event to this URL — the handler ignores events it doesn't recognize.

    Your Convex site URL is in the Convex dashboard under Settings → URL & Deploy Key — it ends in .convex.site.

    5. Initialize the client

    In convex/payments.ts:

    ts
    import { components } from "./_generated/api";
    import { Flutterwave } from "convex-flutterwave";
    
    export const flutterwave = new Flutterwave(components.convexFlutterwave, {
      secretKey: process.env.FLW_SECRET_KEY!,
      webhookSecretHash: process.env.FLW_WEBHOOK_SECRET_HASH!,
    });

    Import flutterwave from this file in any Convex function that needs payments.

  3. 3

    Setup

    convex/payments.ts — your central payments module:

    ts
    import { components } from "./_generated/api";
    import { Flutterwave } from "convex-flutterwave";
    import { action } from "./_generated/server";
    import { v } from "convex/values";
    
    export const flutterwave = new Flutterwave(components.convexFlutterwave, {
      secretKey: process.env.FLW_SECRET_KEY!,
      webhookSecretHash: process.env.FLW_WEBHOOK_SECRET_HASH!,
    });
    
    export const checkout = action({
      args: { email: v.string(), amount: v.number(), redirectUrl: v.string() },
      handler: async (ctx, args) => flutterwave.initializeTransaction(ctx, args),
    });

    convex/http.ts — webhook entry point (shown in ).

  4. 4

    Usage

    Start a checkout

    ts
    export const checkout = action({
      args: { email: v.string(), amount: v.number() },
      handler: async (ctx, args) => {
        return await flutterwave.initializeTransaction(ctx, {
          email: args.email,
          amount: args.amount, // major currency unit — e.g. naira, not kobo
          redirectUrl: "https://yourapp.com/payment/callback",
        });
      },
    });
    // Returns: { paymentLink, txRef }
    // Redirect the customer to paymentLink.

    Verify a transaction

    ts
    export const confirmPayment = action({
      args: { transactionId: v.string() },
      handler: async (ctx, args) => {
        return await flutterwave.verifyTransaction(ctx, args);
      },
    });
    // Returns: { status, txRef, flwRef, transactionId, amount, currency, customerEmail, ... }

    Flutterwave redirects to your redirectUrl with status and tx_ref query params on every outcome, and transaction_id only when a chargeable attempt was made — a card declined at the gateway or an abandoned checkout redirects back with just status=failed and tx_ref, no transaction_id to verify. Handle that case on your result screen rather than assuming transaction_id is always present.

    Read a transaction reactively

    ts
    export const getTransaction = query({
      args: { txRef: v.string() },
      handler: async (ctx, args) => {
        return await flutterwave.getTransaction(ctx, args);
      },
    });
    // Returns: Transaction | null

    List a customer's transactions

    ts
    export const getHistory = query({
      args: { customerEmail: v.string() },
      handler: async (ctx, args) => {
        return await flutterwave.listTransactions(ctx, {
          customerEmail: args.customerEmail,
          limit: 20,
        });
      },
    });
    // Returns: Transaction[] ordered newest first