Bkash Payment with NextJS & TypeScript
Tags: javascript, react, nextjs, typescript
Published: 2024-05-07 09:52:14

# Run code from github
You can get and run code from here [Bkash github repo](https://github.com/arfat-xyz/nextjs-bkash-payment-with-sandbox)
After donwloading code 
- create an `.env`
- Copy bellow code
```
# BKASH INTEGRESION
bkash_username = ''
bkash_password = ''
bkash_api_key = ''
bkash_secret_key = ''

bkash_grant_token_url = https://tokenized.sandbox.bka.sh/v1.2.0-beta/tokenized/checkout/token/grant
bkash_create_payment_url =  https://tokenized.sandbox.bka.sh/v1.2.0-beta/tokenized/checkout/create
bkash_execute_payment_url = https://tokenized.sandbox.bka.sh/v1.2.0-beta/tokenized/checkout/execute
bkash_refund_transaction_url = https://tokenized.sandbox.bka.sh/v1.2.0-beta/tokenized/checkout/payment/refund

bkash_base_url_for_api = "http://localhost:3000"
NEXT_PUBLIC_bkash_base_url_for_frontend = "http://localhost:3000"
```
- Run `npm i`
- Then `npm run dev`

# Create your own
Create a new apps if you don't have any project ye by following [NextJS with Tailwind](https://tailwindcss.com/docs/guides/nextjs)

# Necessary files
1. 3 page(Home, success, callback) 
2. 1 API middleware (/create/bkash_auth)
3. 2 api(/create , /callback)
4. 3 component (callback-component, form-component, success-component)

# Required Packages
- react-hot-toast
- uuid & @types/uuid
- zod

# Creating 3 pages

### Home page
```
import FormComponent from "@/component/form-component";
import { Metadata } from "next";
import { Suspense } from "react";
export const metadata: Metadata = {
  title: "Home | Arfatur Rahman",
  description: "Practice Bkash payment with sandbox",
};
export default function Home() {
  return (

    // Suspense is required for useSearchParams in component inside
    <Suspense>
      <FormComponent />
    </Suspense>
  );
}
```

### Success page
```
import SuccessComponent from "@/component/success-component";
import { Metadata } from "next";
import React from "react";
export const metadata: Metadata = {
  title: "Success | Arfatur Rahman",
  description: "Practice Bkash payment with sandbox",
};
const SuccessPage = () => {
  return <SuccessComponent />;
};

export default SuccessPage;
```

### Callback page
```
"use client";
import CallBackComponent from "@/component/callback-component";
import React, { Suspense } from "react";

const CallBackPage = () => {
  return (
    <Suspense>
      <CallBackComponent />
    </Suspense>
  );
};

export default CallBackPage;
```

# API Middleware
### bkash_auth
```
export const bkash_auth = async () => {
  try {
    const data = await fetch(process.env.bkash_grant_token_url as string, {
      method: "POST",
      body: JSON.stringify({
        app_key: process.env.bkash_api_key,
        app_secret: process.env.bkash_secret_key,
      }),
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
        username: process.env.bkash_username as string,
        password: process.env.bkash_password as string,
      },
    }).then((res) => res.json());

    return data.id_token;
  } catch (error) {
    return new Response((error as any).message || "You're not authorized", {
      status: 401,
    });
  }
```


# Creating 2 API's
## Create API
```
import { z } from "zod";
import { v4 as uuidv4 } from "uuid";
import { bkash_auth } from "./bkash-middleware";

export async function POST(req: Request) {
  try {
    const json = await req.json();
    const { amount } = z
      .object({
        amount: z.string({ required_error: "amount must be string" }),
      })
      .parse(json);
    const id_token = await bkash_auth();
    const data = await fetch(process.env.bkash_create_payment_url as string, {
      method: "POST",
      body: JSON.stringify({
        mode: "0011",
        payerReference: " ",
        callbackURL: `${process.env.bkash_base_url_for_api}/callback?id_token=${id_token}`,
        amount: amount,
        currency: "BDT",
        intent: "sale",
        merchantInvoiceNumber: "Inv" + uuidv4().substring(0, 5),
      }),
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
        authorization: id_token,
        "x-app-key": process.env.bkash_api_key as string,
      },
    }).then((bRes) => bRes.json());
    if (!data.bkashURL) {
      return new Response(JSON.stringify(data), {
        status: 401,
      });
    }
    return new Response(JSON.stringify({ bkashURL: data.bkashURL }), {
      status: 201,
    });
  } catch (error) {
    console.log(error, "from error");
    if (error instanceof z.ZodError) {
      return new Response(JSON.stringify(error.issues), { status: 422 });
    }
    return new Response(null, { status: 500 });
  }
}

```

### Callback API
```
import { z } from "zod";

export async function POST(req: Request) {
  try {
    const json = await req.json();
    const { paymentID, id_token } = z
      .object({
        paymentID: z.string(),
        id_token: z.string(),
      })
      .parse(json);
    const data = await fetch(process.env.bkash_execute_payment_url as string, {
      method: "POST",
      body: JSON.stringify({
        paymentID: paymentID as string,
      }),
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
        authorization: id_token,
        "x-app-key": process.env.bkash_api_key as string,
      },
    })
      .then((bRes) => {
        return bRes.json();
      })
      .catch((e) => console.log(e, "Error from api"));
    if (data && data.statusCode === "0000") {
      // YOu can write your code here After successfully pay
      return new Response(JSON.stringify({ success: true }), { status: 201 });
    } else {
      return new Response(JSON.stringify({ success: false }), { status: 201 });
    }
  } catch (error) {
    console.log((error as any).message, "from error");

    return new Response(null, { status: 500 });
  }
}

```

# After adding codes run bellow command
- Run `npm i`
- Then `npm run dev`