← All packages

Payments · Convex component

convex-paystack

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

npm install convex-paystack
20downloads last week
712downloads 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-paystack

The install and setup steps from the package documentation.

  1. 1

    Install

    bash
    npm install convex-paystack

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

  2. 2

    Quick Start

    Five steps to add Paystack to your Convex app.

    1. Add the component

    In convex/convex.config.ts:

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

    2. Set environment variables

    bash
    npx convex env set PAYSTACK_SECRET_KEY sk_live_xxxxxxxxxxxx

    3. Mount the webhook handler

    In convex/http.ts:

    ts
    import { httpRouter } from "convex/server";
    import { components } from "./_generated/api";
    import { Paystack } from "convex-paystack";
    
    const paystack = new Paystack(components.convexPaystack, {
      secretKey: process.env.PAYSTACK_SECRET_KEY!,
    });
    
    const http = httpRouter();
    
    http.route({
      path: "/webhooks/paystack",
      method: "POST",
      handler: paystack.webhookHandler,
    });
    
    export default http;

    4. Register the webhook in Paystack

    1. In Paystack Dashboard → Settings → API Keys & Webhooks
    2. Set the webhook URL: https://your-deployment.convex.site/webhooks/paystack
    3. Save. Paystack 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 { Paystack } from "convex-paystack";
    
    export const paystack = new Paystack(components.convexPaystack, {
      secretKey: process.env.PAYSTACK_SECRET_KEY!,
    });

    Import paystack 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 { Paystack } from "convex-paystack";
    import { action } from "./_generated/server";
    import { v } from "convex/values";
    
    export const paystack = new Paystack(components.convexPaystack, {
      secretKey: process.env.PAYSTACK_SECRET_KEY!,
    });
    
    export const checkout = action({
      args: { email: v.string(), amount: v.number() },
      handler: async (ctx, args) => paystack.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 paystack.initializeTransaction(ctx, {
          email: args.email,
          amount: args.amount, // subunit — kobo for NGN, pesewas for GHS, cents for USD
          callbackUrl: "https://yourapp.com/payment/callback",
        });
      },
    });
    // Returns: { authorizationUrl, accessCode, reference }
    // Redirect the customer to authorizationUrl.

    Verify a transaction

    ts
    export const confirmPayment = action({
      args: { reference: v.string() },
      handler: async (ctx, args) => {
        return await paystack.verifyTransaction(ctx, args);
      },
    });
    // Returns: { status, reference, amount, currency, channel, paidAt, customerEmail, ... }

    Read a transaction reactively

    ts
    export const getTransaction = query({
      args: { reference: v.string() },
      handler: async (ctx, args) => {
        return await paystack.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 paystack.listTransactions(ctx, {
          customerEmail: args.customerEmail,
          limit: 20,
        });
      },
    });
    // Returns: Transaction[] ordered newest first