<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Walex Eniola</title>
    <description>The latest articles on Forem by Walex Eniola (@walex_eniola_017a0a46b88a).</description>
    <link>https://forem.com/walex_eniola_017a0a46b88a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2571628%2F5c6c1ebf-71be-43d5-88b4-1aa6e07518c7.png</url>
      <title>Forem: Walex Eniola</title>
      <link>https://forem.com/walex_eniola_017a0a46b88a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/walex_eniola_017a0a46b88a"/>
    <language>en</language>
    <item>
      <title>Need Help Setting Up Flutterwave with TypeScript, Express.js, Sequelize, and PostgreSQL</title>
      <dc:creator>Walex Eniola</dc:creator>
      <pubDate>Sun, 15 Dec 2024 01:22:22 +0000</pubDate>
      <link>https://forem.com/walex_eniola_017a0a46b88a/need-help-setting-up-flutterwave-with-typescript-expressjs-sequelize-and-postgresql-jee</link>
      <guid>https://forem.com/walex_eniola_017a0a46b88a/need-help-setting-up-flutterwave-with-typescript-expressjs-sequelize-and-postgresql-jee</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hi DEV Community,&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm currently working on integrating Flutterwave into my application built with TypeScript, Express.js, Sequelize, and PostgreSQL. However, I’ve been facing a few challenges and would appreciate any guidance or resources you can share.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s a summary of what I’ve done so far:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Installed the flutterwave-node-v3 package and configured it with my public and secret keys.&lt;/li&gt;
&lt;li&gt;Created TypeScript functions for payment initialization and verification.&lt;/li&gt;
&lt;li&gt;Used Sequelize to model my database tables (e.g., Tickets and Events).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Issues Encountered:&lt;/strong&gt;&lt;br&gt;
a. When calling flw.initializePayment, I get the error:&lt;br&gt;
TypeError: initializePayment is not a function.&lt;br&gt;
b. Adding TypeScript support is proving tricky since there are no official TypeScript types for flutterwave-node-v3, and writing custom type declarations hasn’t resolved the issue.&lt;br&gt;
c. Need help understanding the best practices for handling asynchronous callbacks and updating event and ticket statuses in the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I’ve Tried:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/types/flutterwave-node-v3.d.ts
declare module 'flutterwave-node-v3' {
    // TypeScript interfaces for the Flutterwave response and request types
    export interface PaymentInitiateResponse {
      status: string;
      message: string;
      data: {
        link: string;
      };
    }

    export interface TransactionVerifyResponse {
      status: string;
      message: string;
      data: {
        tx_ref: string;
        flw_ref: string;
        currency: string;
        status: string;
      };
    }

    export interface Flutterwave {
      initializePayment(
        payload: {
          tx_ref: string;
          amount: number;
          currency: string;
          redirect_url: string;
          customer: {
            email: string;
          };
        }
      ): Promise&amp;lt;PaymentInitiateResponse&amp;gt;;

      TransactionVerify(
        payload: { id: string }
      ): Promise&amp;lt;TransactionVerifyResponse&amp;gt;;
    }

    const Flutterwave: new (publicKey: string, secretKey: string) =&amp;gt; Flutterwave;
    export = Flutterwave;
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Flutterwave from "flutterwave-node-v3";
import { FLWPUBK, FLWSECK } from "../config";

const flw = new Flutterwave(FLWPUBK, FLWSECK);

export const initiatePayment = async (payload: {
  tx_ref: string;
  amount: number;
  currency: string;
  email: string;
  redirect_url: string;
}) =&amp;gt; {
  try {
    const response = await flw.Charge.card({
      tx_ref: payload.tx_ref,
      amount: payload.amount,
      currency: payload.currency,
      redirect_url: payload.redirect_url,
      customer: {
        email: payload.email,
      },
      payment_options: "card", // Optional: specify payment options
    });

    if (response.status === "success") {
      return response.meta.authorization.redirect; // Payment link
    } else {
      throw new Error(response.message || "Failed to initiate payment.");
    }
  } catch (error) {
    console.error("Payment initiation error:", error);
    throw new Error("Failed to initiate payment.");
  }
};
export const verifyPayment = async (transactionId: string) =&amp;gt; {
  try {
    const response = await flw.Transaction.verify({ id: transactionId });

    if (response.status === "success") {
      return response.data;
    } else {
      throw new Error("Payment verification failed.");
    }
  } catch (error) {
    console.error("Payment verification error:", error);
    throw new Error("Failed to verify payment.");
  }
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;`&lt;br&gt;
import { Request, Response } from "express";&lt;br&gt;
import { EventAttribute, EventInstance } from "../models/eventModel";&lt;br&gt;
import { TicketAttribute, TicketInstance } from "../models/ticketModel";&lt;br&gt;
import { v4 as uuidv4 } from "uuid";&lt;br&gt;
import { JwtPayload } from "jsonwebtoken";&lt;br&gt;
import QRCode from "qrcode";&lt;br&gt;
import { NotificationInstance } from "../models/notificationModel";&lt;br&gt;
import { initiatePayment, verifyPayment } from "../interface/payment.dto";&lt;br&gt;
import { BASE_URL, FRONTEND_URL } from "../config";&lt;br&gt;
import { UserAttribute, UserInstance } from "../models/userModel";&lt;/p&gt;

&lt;p&gt;export const purchaseTicket = async (&lt;br&gt;
  req: JwtPayload,&lt;br&gt;
  res: Response&lt;br&gt;
): Promise =&amp;gt; {&lt;br&gt;
  const userId = req.user;&lt;br&gt;
  const { eventId } = req.params;&lt;br&gt;
  const { ticketType,currency } = req.body;&lt;/p&gt;

&lt;p&gt;try {&lt;br&gt;
    const user = (await UserInstance.findOne({&lt;br&gt;
      where: { id: userId },&lt;br&gt;
    })) as unknown as UserAttribute;&lt;br&gt;
    if (!user) {&lt;br&gt;
      return res.status(404).json({ error: "USer not found" });&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const event = (await EventInstance.findOne({
  where: { id: eventId },
})) as unknown as EventAttribute;
if (!event) {
  return res.status(404).json({ error: "Event not found" });
}

if (new Date() &amp;gt; new Date(event.date)) {
  return res
    .status(400)
    .json({ error: "Cannot purchase tickets for expired events" });
}

const ticketPrice = event.ticketType[ticketType];
if (!ticketPrice) {
  return res.status(400).json({ error: "Invalid ticket type" });
}

const ticketId = uuidv4();

const qrCodeData = {
  ticketId,
  userId,
  eventId: event.id,
  ticketType,
  price: ticketPrice,
  purchaseDate: new Date(),
};
const qrCode = await QRCode.toDataURL(JSON.stringify(qrCodeData));

const newTicket = await TicketInstance.create({
  id: ticketId,
  eventId: event.id,
  userId,
  ticketType,
  price: ticketPrice,
  purchaseDate: new Date(),
  qrCode,
  paid: false,
  currency,
  validationStatus: "Invalid",
}) as unknown as TicketAttribute;

const notification = await NotificationInstance.create({
  id: uuidv4(),
  title: "Ticket Purchase Successful",
  message: `You have successfully purchased a ${ticketType} ticket for the event ${event.title}.`,
  userId,
  isRead: false,
});

const paymentLink = await initiatePayment({
  tx_ref: newTicket.id,
  amount: newTicket.price,
  currency: newTicket.currency,
  email: user.email,
  redirect_url: `${BASE_URL}/tickets/callback`,
});

return res.status(201).json({
  message: "Ticket created successfully",
  paymentLink,
  ticket: newTicket,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;} catch (error: any) {&lt;br&gt;
    return res&lt;br&gt;
      .status(500)&lt;br&gt;
      .json({ error: "Failed to purchase ticket", details: error.message });&lt;br&gt;
  }&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;export const paymentVerification = async (&lt;br&gt;
  req: JwtPayload,&lt;br&gt;
  res: Response&lt;br&gt;
): Promise =&amp;gt; {&lt;br&gt;
  const { transaction_id, tx_ref } = req.query;&lt;/p&gt;

&lt;p&gt;try {&lt;br&gt;
    // Verify payment&lt;br&gt;
    const paymentData = await verifyPayment(transaction_id as string);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (paymentData.tx_ref === tx_ref) {
  await TicketInstance.update(
    {
      paid: true,
      validationStatus: "Valid",
      flwRef: paymentData.flw_ref,
      currency: paymentData.currency,
    },
    {
      where: { id: tx_ref },
    }
  );

  const ticket = (await TicketInstance.findOne({
    where: { id: tx_ref },
  })) as unknown as TicketAttribute;
  const event = (await EventInstance.findOne({
    where: { id: ticket?.eventId },
  })) as unknown as EventAttribute;

  if (event) {
    if (event.quantity &amp;lt;= 0) {
      throw new Error("Event is sold out");
    }

    await EventInstance.update(
      {
        quantity: event.quantity - 1,
        sold: event.sold + 1,
      },
      { where: { id: ticket?.eventId } }
    );
  }

  res.redirect(`${FRONTEND_URL}/payment-success`);
} else {
  throw new Error("Transaction reference mismatch");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;} catch (error) {&lt;br&gt;
    console.error(error);&lt;br&gt;
    res.redirect(&lt;code&gt;${FRONTEND_URL}/payment-failed&lt;/code&gt;);&lt;br&gt;
  }&lt;br&gt;
};`&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tech Stack Details:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend Framework: Express.js&lt;/li&gt;
&lt;li&gt;ORM: Sequelize&lt;/li&gt;
&lt;li&gt;Database: PostgreSQL&lt;/li&gt;
&lt;li&gt;Language: TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Questions:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Has anyone successfully integrated Flutterwave into a TypeScript + Express.js project?&lt;/li&gt;
&lt;li&gt;Are there any community-supported type declarations or better approaches to use this package?&lt;/li&gt;
&lt;li&gt;What’s the best way to handle the transaction_id callback for verifying payments and updating database records?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you’ve encountered similar issues or have suggestions (articles, YouTube tutorials, or GitHub repositories), I’d greatly appreciate your help.&lt;/p&gt;

&lt;p&gt;Thanks in advance! 🚀&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>express</category>
      <category>flutterwave</category>
    </item>
  </channel>
</rss>
