@dev_innovations_labs/phonepe-pg-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
File without changes
@@ -0,0 +1,9 @@
1
+ import { PhonePeCredentials, PhonePePaymentInit } from "./types";
2
+ export declare class PhonePeNode {
3
+ private creds;
4
+ constructor(creds: PhonePeCredentials);
5
+ private get urls();
6
+ getToken(): Promise<any>;
7
+ createPayment(data: PhonePePaymentInit): Promise<any>;
8
+ getStatus(merchantId: string, merchantOrderId: string): Promise<any>;
9
+ }
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import { PhonePeCredentials, PhonePePaymentInit } from "./types";
3
+ declare global {
4
+ interface Window {
5
+ PhonePeCheckout: any;
6
+ }
7
+ }
8
+ interface Props extends PhonePeCredentials {
9
+ request: PhonePePaymentInit;
10
+ onSuccess: (data: any) => void;
11
+ onError: (err: any) => void;
12
+ }
13
+ export declare const PhonePeCheckoutWeb: React.FC<Props>;
14
+ export {};
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import { PhonePeCredentials, PhonePePaymentInit } from "./types";
3
+ interface Props extends PhonePeCredentials {
4
+ request: PhonePePaymentInit;
5
+ onSuccess: (data: any) => void;
6
+ onError: (err: any) => void;
7
+ }
8
+ export declare const PhonePeCheckoutNative: React.FC<Props>;
9
+ export {};
package/dist/env.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export declare const PhonePeUrls: {
2
+ production: {
3
+ token: string;
4
+ pay: string;
5
+ status: string;
6
+ script: string;
7
+ };
8
+ sandbox: {
9
+ token: string;
10
+ pay: string;
11
+ status: string;
12
+ script: string;
13
+ };
14
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./PhonePeNode";
2
+ export * from "./PhonePeReact";
3
+ export * from "./types";
@@ -0,0 +1,139 @@
1
+ import axios from 'axios';
2
+ import { v4 } from 'uuid';
3
+ import { useEffect } from 'react';
4
+
5
+ const PhonePeUrls = {
6
+ production: {
7
+ token: "https://api.phonepe.com/apis/identity-manager/v1/oauth/token",
8
+ pay: "https://api.phonepe.com/apis/pg/checkout/v2/pay",
9
+ status: "https://api.phonepe.com/apis/pg/checkout/v2/order/status",
10
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
11
+ },
12
+ sandbox: {
13
+ token: "https://api-preprod.phonepe.com/apis/identity-manager/v1/oauth/token",
14
+ pay: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/pay",
15
+ status: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/order/status",
16
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
17
+ }
18
+ };
19
+
20
+ function normalizeEnvironment(env) {
21
+ const e = String(env).toLowerCase().trim();
22
+ if (e === "production" || e === "prod")
23
+ return "production";
24
+ if (e === "sandbox")
25
+ return "sandbox";
26
+ throw new Error(`Invalid environment "${env}". Expected "Production" or "Sandbox".`);
27
+ }
28
+
29
+ class PhonePeNode {
30
+ constructor(creds) {
31
+ this.creds = creds;
32
+ }
33
+ get urls() {
34
+ const env = normalizeEnvironment(this.creds.environment);
35
+ return PhonePeUrls[env];
36
+ }
37
+ async getToken() {
38
+ const body = new URLSearchParams({
39
+ client_id: this.creds.clientId,
40
+ client_secret: this.creds.clientSecret,
41
+ grant_type: "client_credentials",
42
+ client_version: "1"
43
+ });
44
+ const res = await axios.post(this.urls.token, body, {
45
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
46
+ });
47
+ return res.data.access_token;
48
+ }
49
+ async createPayment(data) {
50
+ const token = await this.getToken();
51
+ const payload = {
52
+ merchantId: data.merchantId,
53
+ merchantOrderId: v4(),
54
+ merchantTransactionId: v4(),
55
+ amount: data.amount,
56
+ mobileNumber: data.mobileNumber,
57
+ redirectUrl: data.redirectUrl,
58
+ callbackUrl: data.callbackUrl,
59
+ deviceContext: data.deviceContext,
60
+ paymentScope: data.paymentScope,
61
+ };
62
+ const res = await axios.post(this.urls.pay, payload, {
63
+ headers: {
64
+ "Content-Type": "application/json",
65
+ Authorization: `O-Bearer ${token}`,
66
+ }
67
+ });
68
+ return res.data;
69
+ }
70
+ async getStatus(merchantId, merchantOrderId) {
71
+ const token = await this.getToken();
72
+ const res = await axios.post(this.urls.status, {
73
+ merchantId,
74
+ merchantOrderId
75
+ }, {
76
+ headers: {
77
+ "Content-Type": "application/json",
78
+ Authorization: `O-Bearer ${token}`,
79
+ }
80
+ });
81
+ return res.data;
82
+ }
83
+ }
84
+
85
+ const PhonePeCheckoutWeb = ({ environment, clientId, clientSecret, request, onSuccess, onError }) => {
86
+ const env = normalizeEnvironment(environment);
87
+ const urls = PhonePeUrls[env];
88
+ if (!urls) {
89
+ onError(`Invalid environment: ${environment}`);
90
+ return;
91
+ }
92
+ useEffect(() => {
93
+ const script = document.createElement("script");
94
+ script.src = urls.script;
95
+ script.async = true;
96
+ document.body.appendChild(script);
97
+ script.onload = () => init();
98
+ }, []);
99
+ const init = async () => {
100
+ try {
101
+ const tokenResp = await fetch(urls.token, {
102
+ method: "POST",
103
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
104
+ body: new URLSearchParams({
105
+ client_id: clientId,
106
+ client_secret: clientSecret,
107
+ grant_type: "client_credentials",
108
+ client_version: "1"
109
+ })
110
+ });
111
+ const token = (await tokenResp.json()).access_token;
112
+ const payload = {
113
+ ...request,
114
+ merchantOrderId: v4(),
115
+ merchantTransactionId: v4()
116
+ };
117
+ const payResp = await fetch(urls.pay, {
118
+ method: "POST",
119
+ headers: {
120
+ "Content-Type": "application/json",
121
+ Authorization: `O-Bearer ${token}`
122
+ },
123
+ body: JSON.stringify(payload)
124
+ });
125
+ const payData = await payResp.json();
126
+ window.PhonePeCheckout.transact({
127
+ tokenUrl: payData.redirectUrl,
128
+ type: "IFRAME",
129
+ callback: () => onSuccess(payData)
130
+ });
131
+ }
132
+ catch (err) {
133
+ onError(err);
134
+ }
135
+ };
136
+ return null;
137
+ };
138
+
139
+ export { PhonePeCheckoutWeb, PhonePeNode };
package/dist/index.js ADDED
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ var axios = require('axios');
4
+ var uuid = require('uuid');
5
+ var react = require('react');
6
+
7
+ const PhonePeUrls = {
8
+ production: {
9
+ token: "https://api.phonepe.com/apis/identity-manager/v1/oauth/token",
10
+ pay: "https://api.phonepe.com/apis/pg/checkout/v2/pay",
11
+ status: "https://api.phonepe.com/apis/pg/checkout/v2/order/status",
12
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
13
+ },
14
+ sandbox: {
15
+ token: "https://api-preprod.phonepe.com/apis/identity-manager/v1/oauth/token",
16
+ pay: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/pay",
17
+ status: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/order/status",
18
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
19
+ }
20
+ };
21
+
22
+ function normalizeEnvironment(env) {
23
+ const e = String(env).toLowerCase().trim();
24
+ if (e === "production" || e === "prod")
25
+ return "production";
26
+ if (e === "sandbox")
27
+ return "sandbox";
28
+ throw new Error(`Invalid environment "${env}". Expected "Production" or "Sandbox".`);
29
+ }
30
+
31
+ class PhonePeNode {
32
+ constructor(creds) {
33
+ this.creds = creds;
34
+ }
35
+ get urls() {
36
+ const env = normalizeEnvironment(this.creds.environment);
37
+ return PhonePeUrls[env];
38
+ }
39
+ async getToken() {
40
+ const body = new URLSearchParams({
41
+ client_id: this.creds.clientId,
42
+ client_secret: this.creds.clientSecret,
43
+ grant_type: "client_credentials",
44
+ client_version: "1"
45
+ });
46
+ const res = await axios.post(this.urls.token, body, {
47
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
48
+ });
49
+ return res.data.access_token;
50
+ }
51
+ async createPayment(data) {
52
+ const token = await this.getToken();
53
+ const payload = {
54
+ merchantId: data.merchantId,
55
+ merchantOrderId: uuid.v4(),
56
+ merchantTransactionId: uuid.v4(),
57
+ amount: data.amount,
58
+ mobileNumber: data.mobileNumber,
59
+ redirectUrl: data.redirectUrl,
60
+ callbackUrl: data.callbackUrl,
61
+ deviceContext: data.deviceContext,
62
+ paymentScope: data.paymentScope,
63
+ };
64
+ const res = await axios.post(this.urls.pay, payload, {
65
+ headers: {
66
+ "Content-Type": "application/json",
67
+ Authorization: `O-Bearer ${token}`,
68
+ }
69
+ });
70
+ return res.data;
71
+ }
72
+ async getStatus(merchantId, merchantOrderId) {
73
+ const token = await this.getToken();
74
+ const res = await axios.post(this.urls.status, {
75
+ merchantId,
76
+ merchantOrderId
77
+ }, {
78
+ headers: {
79
+ "Content-Type": "application/json",
80
+ Authorization: `O-Bearer ${token}`,
81
+ }
82
+ });
83
+ return res.data;
84
+ }
85
+ }
86
+
87
+ const PhonePeCheckoutWeb = ({ environment, clientId, clientSecret, request, onSuccess, onError }) => {
88
+ const env = normalizeEnvironment(environment);
89
+ const urls = PhonePeUrls[env];
90
+ if (!urls) {
91
+ onError(`Invalid environment: ${environment}`);
92
+ return;
93
+ }
94
+ react.useEffect(() => {
95
+ const script = document.createElement("script");
96
+ script.src = urls.script;
97
+ script.async = true;
98
+ document.body.appendChild(script);
99
+ script.onload = () => init();
100
+ }, []);
101
+ const init = async () => {
102
+ try {
103
+ const tokenResp = await fetch(urls.token, {
104
+ method: "POST",
105
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
106
+ body: new URLSearchParams({
107
+ client_id: clientId,
108
+ client_secret: clientSecret,
109
+ grant_type: "client_credentials",
110
+ client_version: "1"
111
+ })
112
+ });
113
+ const token = (await tokenResp.json()).access_token;
114
+ const payload = {
115
+ ...request,
116
+ merchantOrderId: uuid.v4(),
117
+ merchantTransactionId: uuid.v4()
118
+ };
119
+ const payResp = await fetch(urls.pay, {
120
+ method: "POST",
121
+ headers: {
122
+ "Content-Type": "application/json",
123
+ Authorization: `O-Bearer ${token}`
124
+ },
125
+ body: JSON.stringify(payload)
126
+ });
127
+ const payData = await payResp.json();
128
+ window.PhonePeCheckout.transact({
129
+ tokenUrl: payData.redirectUrl,
130
+ type: "IFRAME",
131
+ callback: () => onSuccess(payData)
132
+ });
133
+ }
134
+ catch (err) {
135
+ onError(err);
136
+ }
137
+ };
138
+ return null;
139
+ };
140
+
141
+ exports.PhonePeCheckoutWeb = PhonePeCheckoutWeb;
142
+ exports.PhonePeNode = PhonePeNode;
@@ -0,0 +1 @@
1
+ export * from "./PhonePeReactNative";
@@ -0,0 +1,81 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import { WebView } from 'react-native-webview';
4
+ import { v4 } from 'uuid';
5
+
6
+ const PhonePeUrls = {
7
+ production: {
8
+ token: "https://api.phonepe.com/apis/identity-manager/v1/oauth/token",
9
+ pay: "https://api.phonepe.com/apis/pg/checkout/v2/pay",
10
+ status: "https://api.phonepe.com/apis/pg/checkout/v2/order/status",
11
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
12
+ },
13
+ sandbox: {
14
+ token: "https://api-preprod.phonepe.com/apis/identity-manager/v1/oauth/token",
15
+ pay: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/pay",
16
+ status: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/order/status",
17
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
18
+ }
19
+ };
20
+
21
+ function normalizeEnvironment(env) {
22
+ const e = String(env).toLowerCase().trim();
23
+ if (e === "production" || e === "prod")
24
+ return "production";
25
+ if (e === "sandbox")
26
+ return "sandbox";
27
+ throw new Error(`Invalid environment "${env}". Expected "Production" or "Sandbox".`);
28
+ }
29
+
30
+ const PhonePeCheckoutNative = ({ clientId, clientSecret, environment, request, onSuccess, onError }) => {
31
+ const [url, setUrl] = useState();
32
+ const env = normalizeEnvironment(environment);
33
+ const urls = PhonePeUrls[env];
34
+ if (!urls) {
35
+ onError(`Invalid environment: ${environment}`);
36
+ return;
37
+ }
38
+ useEffect(() => {
39
+ init();
40
+ }, []);
41
+ const init = async () => {
42
+ try {
43
+ const tokenResp = await fetch(urls.token, {
44
+ method: "POST",
45
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
46
+ body: new URLSearchParams({
47
+ client_id: clientId,
48
+ client_secret: clientSecret,
49
+ grant_type: "client_credentials",
50
+ client_version: "1"
51
+ })
52
+ });
53
+ const token = (await tokenResp.json()).access_token;
54
+ const payload = {
55
+ ...request,
56
+ merchantOrderId: v4(),
57
+ merchantTransactionId: v4()
58
+ };
59
+ const payResp = await fetch(urls.pay, {
60
+ method: "POST",
61
+ headers: {
62
+ "Content-Type": "application/json",
63
+ Authorization: `O-Bearer ${token}`
64
+ },
65
+ body: JSON.stringify(payload)
66
+ });
67
+ const { redirectUrl } = await payResp.json();
68
+ setUrl(redirectUrl);
69
+ }
70
+ catch (err) {
71
+ onError(err);
72
+ }
73
+ };
74
+ return url ? (jsx(WebView, { source: { uri: url }, onNavigationStateChange: (nav) => {
75
+ if (nav.url.includes("callback")) {
76
+ onSuccess(nav);
77
+ }
78
+ } })) : null;
79
+ };
80
+
81
+ export { PhonePeCheckoutNative };
package/dist/native.js ADDED
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var reactNativeWebview = require('react-native-webview');
6
+ var uuid = require('uuid');
7
+
8
+ const PhonePeUrls = {
9
+ production: {
10
+ token: "https://api.phonepe.com/apis/identity-manager/v1/oauth/token",
11
+ pay: "https://api.phonepe.com/apis/pg/checkout/v2/pay",
12
+ status: "https://api.phonepe.com/apis/pg/checkout/v2/order/status",
13
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
14
+ },
15
+ sandbox: {
16
+ token: "https://api-preprod.phonepe.com/apis/identity-manager/v1/oauth/token",
17
+ pay: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/pay",
18
+ status: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/order/status",
19
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
20
+ }
21
+ };
22
+
23
+ function normalizeEnvironment(env) {
24
+ const e = String(env).toLowerCase().trim();
25
+ if (e === "production" || e === "prod")
26
+ return "production";
27
+ if (e === "sandbox")
28
+ return "sandbox";
29
+ throw new Error(`Invalid environment "${env}". Expected "Production" or "Sandbox".`);
30
+ }
31
+
32
+ const PhonePeCheckoutNative = ({ clientId, clientSecret, environment, request, onSuccess, onError }) => {
33
+ const [url, setUrl] = react.useState();
34
+ const env = normalizeEnvironment(environment);
35
+ const urls = PhonePeUrls[env];
36
+ if (!urls) {
37
+ onError(`Invalid environment: ${environment}`);
38
+ return;
39
+ }
40
+ react.useEffect(() => {
41
+ init();
42
+ }, []);
43
+ const init = async () => {
44
+ try {
45
+ const tokenResp = await fetch(urls.token, {
46
+ method: "POST",
47
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
48
+ body: new URLSearchParams({
49
+ client_id: clientId,
50
+ client_secret: clientSecret,
51
+ grant_type: "client_credentials",
52
+ client_version: "1"
53
+ })
54
+ });
55
+ const token = (await tokenResp.json()).access_token;
56
+ const payload = {
57
+ ...request,
58
+ merchantOrderId: uuid.v4(),
59
+ merchantTransactionId: uuid.v4()
60
+ };
61
+ const payResp = await fetch(urls.pay, {
62
+ method: "POST",
63
+ headers: {
64
+ "Content-Type": "application/json",
65
+ Authorization: `O-Bearer ${token}`
66
+ },
67
+ body: JSON.stringify(payload)
68
+ });
69
+ const { redirectUrl } = await payResp.json();
70
+ setUrl(redirectUrl);
71
+ }
72
+ catch (err) {
73
+ onError(err);
74
+ }
75
+ };
76
+ return url ? (jsxRuntime.jsx(reactNativeWebview.WebView, { source: { uri: url }, onNavigationStateChange: (nav) => {
77
+ if (nav.url.includes("callback")) {
78
+ onSuccess(nav);
79
+ }
80
+ } })) : null;
81
+ };
82
+
83
+ exports.PhonePeCheckoutNative = PhonePeCheckoutNative;
@@ -0,0 +1,15 @@
1
+ export type PhonePeEnvironment = "Production" | "Sandbox";
2
+ export interface PhonePeCredentials {
3
+ clientId: string;
4
+ clientSecret: string;
5
+ environment: PhonePeEnvironment;
6
+ }
7
+ export interface PhonePePaymentInit {
8
+ merchantId: string;
9
+ amount: number;
10
+ mobileNumber?: string;
11
+ redirectUrl: string;
12
+ callbackUrl: string;
13
+ deviceContext?: any;
14
+ paymentScope?: string;
15
+ }
@@ -0,0 +1,2 @@
1
+ import { PhonePeEnvironment } from "./types";
2
+ export declare function normalizeEnvironment(env: PhonePeEnvironment): "production" | "sandbox";
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@dev_innovations_labs/phonepe-pg-sdk",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+
6
+ "keywords": [
7
+ "phonepe",
8
+ "phonepe-pg",
9
+ "payment-gateway",
10
+ "pg-sdk",
11
+ "checkout-v2",
12
+ "upi",
13
+ "react",
14
+ "react-native",
15
+ "nodejs",
16
+ "javascript",
17
+ "typescript",
18
+ "web-payments"
19
+ ],
20
+
21
+ "main": "dist/index.js",
22
+ "module": "dist/index.esm.js",
23
+ "types": "dist/index.d.ts",
24
+
25
+ "author": {
26
+ "name": "Dev Innovations Labs"
27
+ },
28
+
29
+ "exports": {
30
+ ".": {
31
+ "import": "./dist/index.esm.js",
32
+ "require": "./dist/index.js",
33
+ "types": "./dist/index.d.ts"
34
+ },
35
+ "./native": {
36
+ "import": "./dist/native.esm.js",
37
+ "require": "./dist/native.js",
38
+ "types": "./dist/native.d.ts"
39
+ }
40
+ },
41
+
42
+ "scripts": {
43
+ "build": "rollup -c"
44
+ },
45
+
46
+ "dependencies": {
47
+ "axios": "^1.6.0",
48
+ "uuid": "^9.0.0"
49
+ },
50
+
51
+ "peerDependencies": {
52
+ "react": "*",
53
+ "react-native": "*",
54
+ "react-native-webview": "*"
55
+ },
56
+
57
+ "peerDependenciesMeta": {
58
+ "react-native-webview": {
59
+ "optional": true
60
+ }
61
+ },
62
+
63
+ "devDependencies": {
64
+ "typescript": "^5.3.3",
65
+ "rollup": "^4.9.0",
66
+ "rollup-plugin-typescript2": "^0.34.1"
67
+ },
68
+
69
+ "publishConfig": {
70
+ "access": "public"
71
+ }
72
+ }
@@ -0,0 +1,26 @@
1
+ import typescript from "rollup-plugin-typescript2";
2
+
3
+ export default [
4
+ {
5
+ input: "src/index.ts",
6
+ output: [
7
+ { file: "dist/index.js", format: "cjs" },
8
+ { file: "dist/index.esm.js", format: "esm" }
9
+ ],
10
+ plugins: [typescript()],
11
+ external: ["axios", "uuid", "react", "react/jsx-runtime", "react-native", "react-native-webview"]
12
+ },
13
+ {
14
+ input: "src/native.ts",
15
+ output: [
16
+ { file: "dist/native.js", format: "cjs" },
17
+ { file: "dist/native.esm.js", format: "esm" }
18
+ ],
19
+ plugins: [typescript()],
20
+ external: [
21
+ "react",
22
+ "react-native",
23
+ "react-native-webview"
24
+ ]
25
+ }
26
+ ];
@@ -0,0 +1,74 @@
1
+ import axios from "axios";
2
+ import { v4 as uuidv4 } from "uuid";
3
+ import { PhonePeCredentials, PhonePePaymentInit } from "./types";
4
+ import { PhonePeUrls } from "./env";
5
+ import { normalizeEnvironment } from "./utils";
6
+
7
+ export class PhonePeNode {
8
+ private creds: PhonePeCredentials;
9
+
10
+ constructor(creds: PhonePeCredentials) {
11
+ this.creds = creds;
12
+ }
13
+
14
+ private get urls() {
15
+ const env = normalizeEnvironment(this.creds.environment);
16
+ return PhonePeUrls[env];
17
+ }
18
+
19
+ async getToken() {
20
+ const body = new URLSearchParams({
21
+ client_id: this.creds.clientId,
22
+ client_secret: this.creds.clientSecret,
23
+ grant_type: "client_credentials",
24
+ client_version: "1"
25
+ });
26
+
27
+ const res = await axios.post(this.urls.token, body, {
28
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
29
+ });
30
+
31
+ return res.data.access_token;
32
+ }
33
+
34
+ async createPayment(data: PhonePePaymentInit) {
35
+ const token = await this.getToken();
36
+
37
+ const payload = {
38
+ merchantId: data.merchantId,
39
+ merchantOrderId: uuidv4(),
40
+ merchantTransactionId: uuidv4(),
41
+ amount: data.amount,
42
+ mobileNumber: data.mobileNumber,
43
+ redirectUrl: data.redirectUrl,
44
+ callbackUrl: data.callbackUrl,
45
+ deviceContext: data.deviceContext,
46
+ paymentScope: data.paymentScope,
47
+ };
48
+
49
+ const res = await axios.post(this.urls.pay, payload, {
50
+ headers: {
51
+ "Content-Type": "application/json",
52
+ Authorization: `O-Bearer ${token}`,
53
+ }
54
+ });
55
+
56
+ return res.data;
57
+ }
58
+
59
+ async getStatus(merchantId: string, merchantOrderId: string) {
60
+ const token = await this.getToken();
61
+
62
+ const res = await axios.post(this.urls.status, {
63
+ merchantId,
64
+ merchantOrderId
65
+ }, {
66
+ headers: {
67
+ "Content-Type": "application/json",
68
+ Authorization: `O-Bearer ${token}`,
69
+ }
70
+ });
71
+
72
+ return res.data;
73
+ }
74
+ }
@@ -0,0 +1,89 @@
1
+ import React, { useEffect } from "react";
2
+ import { v4 as uuidv4 } from "uuid";
3
+ import { PhonePeCredentials, PhonePePaymentInit } from "./types";
4
+ import { PhonePeUrls } from "./env";
5
+ import { normalizeEnvironment } from "./utils";
6
+
7
+ declare global {
8
+ interface Window {
9
+ PhonePeCheckout: any;
10
+ }
11
+ }
12
+
13
+ interface Props extends PhonePeCredentials {
14
+ request: PhonePePaymentInit;
15
+ onSuccess: (data: any) => void;
16
+ onError: (err: any) => void;
17
+ }
18
+
19
+ export const PhonePeCheckoutWeb: React.FC<Props> = ({
20
+ environment,
21
+ clientId,
22
+ clientSecret,
23
+ request,
24
+ onSuccess,
25
+ onError
26
+ }) => {
27
+
28
+ const env = normalizeEnvironment(environment);
29
+ const urls = PhonePeUrls[env];
30
+
31
+ if (!urls) {
32
+ onError(`Invalid environment: ${environment}`);
33
+ return;
34
+ }
35
+
36
+
37
+ useEffect(() => {
38
+ const script = document.createElement("script");
39
+ script.src = urls.script;
40
+ script.async = true;
41
+ document.body.appendChild(script);
42
+
43
+ script.onload = () => init();
44
+ }, []);
45
+
46
+ const init = async () => {
47
+ try {
48
+ const tokenResp = await fetch(urls.token, {
49
+ method: "POST",
50
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
51
+ body: new URLSearchParams({
52
+ client_id: clientId,
53
+ client_secret: clientSecret,
54
+ grant_type: "client_credentials",
55
+ client_version: "1"
56
+ })
57
+ });
58
+
59
+ const token = (await tokenResp.json()).access_token;
60
+
61
+ const payload = {
62
+ ...request,
63
+ merchantOrderId: uuidv4(),
64
+ merchantTransactionId: uuidv4()
65
+ };
66
+
67
+ const payResp = await fetch(urls.pay, {
68
+ method: "POST",
69
+ headers: {
70
+ "Content-Type": "application/json",
71
+ Authorization: `O-Bearer ${token}`
72
+ },
73
+ body: JSON.stringify(payload)
74
+ });
75
+
76
+ const payData = await payResp.json();
77
+
78
+ window.PhonePeCheckout.transact({
79
+ tokenUrl: payData.redirectUrl,
80
+ type: "IFRAME",
81
+ callback: () => onSuccess(payData)
82
+ });
83
+ } catch (err) {
84
+ onError(err);
85
+ }
86
+ };
87
+
88
+ return null;
89
+ };
@@ -0,0 +1,81 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import { WebView } from "react-native-webview";
3
+ import { v4 } from "uuid";
4
+ import { PhonePeUrls } from "./env";
5
+ import { PhonePeCredentials, PhonePePaymentInit } from "./types";
6
+ import { normalizeEnvironment } from "./utils";
7
+
8
+ interface Props extends PhonePeCredentials {
9
+ request: PhonePePaymentInit;
10
+ onSuccess: (data: any) => void;
11
+ onError: (err: any) => void;
12
+ }
13
+
14
+ export const PhonePeCheckoutNative: React.FC<Props> = ({
15
+ clientId,
16
+ clientSecret,
17
+ environment,
18
+ request,
19
+ onSuccess,
20
+ onError
21
+ }) => {
22
+ const [url, setUrl] = useState<string>();
23
+ const env = normalizeEnvironment(environment);
24
+ const urls = PhonePeUrls[env];
25
+
26
+ if (!urls) {
27
+ onError(`Invalid environment: ${environment}`);
28
+ return;
29
+ }
30
+
31
+ useEffect(() => {
32
+ init();
33
+ }, []);
34
+
35
+ const init = async () => {
36
+ try {
37
+ const tokenResp = await fetch(urls.token, {
38
+ method: "POST",
39
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
40
+ body: new URLSearchParams({
41
+ client_id: clientId,
42
+ client_secret: clientSecret,
43
+ grant_type: "client_credentials",
44
+ client_version: "1"
45
+ })
46
+ });
47
+ const token = (await tokenResp.json()).access_token;
48
+
49
+ const payload = {
50
+ ...request,
51
+ merchantOrderId: v4(),
52
+ merchantTransactionId: v4()
53
+ };
54
+
55
+ const payResp = await fetch(urls.pay, {
56
+ method: "POST",
57
+ headers: {
58
+ "Content-Type": "application/json",
59
+ Authorization: `O-Bearer ${token}`
60
+ },
61
+ body: JSON.stringify(payload)
62
+ });
63
+
64
+ const { redirectUrl } = await payResp.json();
65
+ setUrl(redirectUrl);
66
+ } catch (err) {
67
+ onError(err);
68
+ }
69
+ };
70
+
71
+ return url ? (
72
+ <WebView
73
+ source={{ uri: url }}
74
+ onNavigationStateChange={(nav) => {
75
+ if (nav.url.includes("callback")) {
76
+ onSuccess(nav);
77
+ }
78
+ }}
79
+ />
80
+ ) : null;
81
+ };
package/src/env.ts ADDED
@@ -0,0 +1,15 @@
1
+ export const PhonePeUrls = {
2
+ production: {
3
+ token: "https://api.phonepe.com/apis/identity-manager/v1/oauth/token",
4
+ pay: "https://api.phonepe.com/apis/pg/checkout/v2/pay",
5
+ status: "https://api.phonepe.com/apis/pg/checkout/v2/order/status",
6
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
7
+ },
8
+
9
+ sandbox: {
10
+ token: "https://api-preprod.phonepe.com/apis/identity-manager/v1/oauth/token",
11
+ pay: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/pay",
12
+ status: "https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/order/status",
13
+ script: "https://mercury.phonepe.com/web/bundle/checkout.js",
14
+ }
15
+ };
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./PhonePeNode";
2
+ export * from "./PhonePeReact";
3
+ export * from "./types";
package/src/native.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./PhonePeReactNative";
@@ -0,0 +1,4 @@
1
+ declare module "react-native-webview" {
2
+ import { ComponentType } from "react";
3
+ export const WebView: ComponentType<any>;
4
+ }
package/src/types.ts ADDED
@@ -0,0 +1,17 @@
1
+ export type PhonePeEnvironment = "Production" | "Sandbox";
2
+
3
+ export interface PhonePeCredentials {
4
+ clientId: string;
5
+ clientSecret: string;
6
+ environment: PhonePeEnvironment;
7
+ }
8
+
9
+ export interface PhonePePaymentInit {
10
+ merchantId: string;
11
+ amount: number;
12
+ mobileNumber?: string;
13
+ redirectUrl: string;
14
+ callbackUrl: string;
15
+ deviceContext?: any;
16
+ paymentScope?: string;
17
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { PhonePeEnvironment } from "./types";
2
+
3
+ export function normalizeEnvironment(env: PhonePeEnvironment): "production" | "sandbox" {
4
+ const e = String(env).toLowerCase().trim();
5
+
6
+ if (e === "production" || e === "prod") return "production";
7
+ if (e === "sandbox") return "sandbox";
8
+
9
+ throw new Error(
10
+ `Invalid environment "${env}". Expected "Production" or "Sandbox".`
11
+ );
12
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "declaration": true,
6
+ "jsx": "react-jsx",
7
+ "esModuleInterop": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "skipLibCheck": true,
10
+ "moduleResolution": "Node",
11
+ "outDir": "dist"
12
+ },
13
+ "include": ["src"]
14
+ }