add readme
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
STATIC_DIR='./client'
|
||||||
|
PAYSTACK_SECRET_KEY=
|
||||||
|
PORT='5000'
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 PaystackOSS
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# Paystack Subscriptions Sample App
|
||||||
|
|
||||||
|
This sample application shows how to integrate Paystack's Subscriptions API in your apps. For the official documentation for Paystack Subscriptions, [head over to the docs](https://paystack.com/docs/payments/subscriptions)
|
||||||
|
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|
View a live demo of the app [here]().
|
||||||
|
|
||||||
|
## Get Started
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
- **A Paystack account**: If you don't already have one, [sign up for a Paystack account](https://dashboard.paystack.com/#/signup). You'll need to do this to get your API keys.
|
||||||
|
- **API keys**: You can grab these [from your Paystack dashboard](https://dashboard.paystack.com/#/settings/developers)
|
||||||
|
- **Existing plans**: You'll need to have existing (active) plan objects that you can subscribe your customers to. If you don't already have any plans, you can just create a couple [from your Paystack dashboard](https://dashboard.paystack.com/#/plans?status=active)
|
||||||
|
|
||||||
|
### Running the sample locally
|
||||||
|
|
||||||
|
1. Clone this repo:
|
||||||
|
```
|
||||||
|
git clone https://github.com/PaystackOSS/sample-subscriptions-app
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Navigate to the root directory and install dependencies
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Rename the `.env.example` file to `.env` and add your Paystack secret key. You can also change the default port from 5000 to a port of your choosing:
|
||||||
|
|
||||||
|
```
|
||||||
|
PAYSTACK_SECRET_KEY=sk_domain_xxxxxx
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Start the application
|
||||||
|
|
||||||
|
```
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Visit http://localhost:5000 in your browser to interact with the app. You should be able to signup/login, subscribe to a plan, and view/manage your existing plan(s).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
If you notice any issues with this app, please [open an issue](https://github.com/PaystackOSS/sample-subscriptions-app/issues/new). PRs are also more than welcome, so feel free to [submit a PR](https://github.com/PaystackOSS/sample-subscriptions-app/compare) to fix an issue, or add a new feature!
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This repository is made available under the MIT license. Read [LICENSE.md](https://github.com/PaystackOSS/sample-subscriptions-app/blob/master/LICENSE.md) for more information.
|
||||||
|
|
||||||
|
|||||||
+19
-16
@@ -1,6 +1,6 @@
|
|||||||
window.addEventListener("DOMContentLoaded", async () => {
|
window.addEventListener('DOMContentLoaded', async () => {
|
||||||
const customer_id = window.localStorage.getItem("customer_id");
|
const customer_id = window.localStorage.getItem('customer_id');
|
||||||
const customer_email = window.localStorage.getItem("customer_email");
|
const customer_email = window.localStorage.getItem('customer_email');
|
||||||
|
|
||||||
const subscriptions = await fetch(
|
const subscriptions = await fetch(
|
||||||
`/subscription?customer=${customer_id}`
|
`/subscription?customer=${customer_id}`
|
||||||
@@ -8,7 +8,7 @@ window.addEventListener("DOMContentLoaded", async () => {
|
|||||||
let subscription = subscriptions[0];
|
let subscription = subscriptions[0];
|
||||||
|
|
||||||
if (subscription) {
|
if (subscription) {
|
||||||
const subscriptionInfoDiv = document.getElementById("subscription-info");
|
const subscriptionInfoDiv = document.getElementById('subscription-info');
|
||||||
subscriptionInfoDiv.innerHTML = `
|
subscriptionInfoDiv.innerHTML = `
|
||||||
<hr>
|
<hr>
|
||||||
<p>Hi ${customer_email}<p>
|
<p>Hi ${customer_email}<p>
|
||||||
@@ -16,6 +16,9 @@ window.addEventListener("DOMContentLoaded", async () => {
|
|||||||
<p>
|
<p>
|
||||||
Status: ${subscription.status}
|
Status: ${subscription.status}
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Subscription Code: ${subscription.subscription_code}
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Card on file: ${subscription.authorization.brand} card ending in ${
|
Card on file: ${subscription.authorization.brand} card ending in ${
|
||||||
subscription.authorization.last4
|
subscription.authorization.last4
|
||||||
@@ -32,22 +35,22 @@ window.addEventListener("DOMContentLoaded", async () => {
|
|||||||
}" target="_blank"> Manage subscription </a><br />
|
}" target="_blank"> Manage subscription </a><br />
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
const plans = await fetch("/plans", {
|
const plans = await fetch('/plans', {
|
||||||
method: "get",
|
method: 'get',
|
||||||
})
|
})
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.catch((error) => console.log(error));
|
.catch((error) => console.log(error));
|
||||||
|
|
||||||
let accountDashDiv = document.getElementById("account-dashboard");
|
let accountDashDiv = document.getElementById('account-dashboard');
|
||||||
accountDashDiv.innerHTML +=
|
accountDashDiv.innerHTML +=
|
||||||
"<p>You are currently not on any plan. Select a plan below to subscribe.</p>";
|
'<p>You are currently not on any plan. Select a plan below to subscribe.</p>';
|
||||||
|
|
||||||
let selectPlanDiv = document.createElement("div");
|
let selectPlanDiv = document.createElement('div');
|
||||||
selectPlanDiv.style.display = "flex";
|
selectPlanDiv.style.display = 'flex';
|
||||||
selectPlanDiv.style.flexDirection = "row";
|
selectPlanDiv.style.flexDirection = 'row';
|
||||||
|
|
||||||
plans.forEach((plan) => {
|
plans.forEach((plan) => {
|
||||||
let planDiv = document.createElement("div");
|
let planDiv = document.createElement('div');
|
||||||
planDiv.innerHTML = `
|
planDiv.innerHTML = `
|
||||||
<div class="card" style="width: 18rem; margin: 1rem; text-align: center">
|
<div class="card" style="width: 18rem; margin: 1rem; text-align: center">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -70,11 +73,11 @@ window.addEventListener("DOMContentLoaded", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function signUpForPlan(plan_code) {
|
async function signUpForPlan(plan_code) {
|
||||||
let email = window.localStorage.getItem("customer_email");
|
let email = window.localStorage.getItem('customer_email');
|
||||||
let { authorization_url } = await fetch("/initialize-transaction-with-plan", {
|
let { authorization_url } = await fetch('/initialize-transaction-with-plan', {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email,
|
email,
|
||||||
|
|||||||
Generated
+7
-1084
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -1,18 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "subscriptions-example",
|
"name": "server",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {},
|
"scripts": {
|
||||||
|
"start": "node server.js",
|
||||||
|
"dev": "nodemon server.js"
|
||||||
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@paystack/paystack-sdk": "^1.0.0-beta.6",
|
"@paystack/paystack-sdk": "^1.0.1",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"express": "^4.18.1"
|
"express": "^4.18.1"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"nodemon": "^2.0.19"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,40 @@
|
|||||||
require("dotenv").config({ path: "../.env" });
|
require('dotenv').config({ path: './.env' });
|
||||||
const express = require("express");
|
const express = require('express');
|
||||||
const port = process.env.PORT;
|
const { resolve } = require('path');
|
||||||
const { resolve } = require("path");
|
const Paystack = require('@paystack/paystack-sdk');
|
||||||
const Paystack = require("@paystack/paystack-sdk");
|
const crypto = require('crypto');
|
||||||
const crypto = require("crypto");
|
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const paystack = new Paystack(process.env.PAYSTACK_SECRET_KEY);
|
const paystack = new Paystack(process.env.PAYSTACK_SECRET_KEY);
|
||||||
const plan_codes = ["PLN_12qw4oagab13zvy", "PLN_yb73itushktdpth"];
|
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
app.use(express.static(process.env.STATIC_DIR));
|
app.use(express.static(process.env.STATIC_DIR));
|
||||||
|
|
||||||
app.get("/", async (req, res) => {
|
app.get('/', async (req, res) => {
|
||||||
const path = resolve(process.env.STATIC_DIR + "/login.html");
|
const path = resolve(process.env.STATIC_DIR + '/login.html');
|
||||||
res.sendFile(path);
|
res.sendFile(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/plans", async (req, res) => {
|
app.get('/plans', async (req, res) => {
|
||||||
let fetchPlansResponse = await paystack.plan.list({});
|
let fetchPlansResponse = await paystack.plan.list({});
|
||||||
|
|
||||||
if (fetchPlansResponse.status === false) {
|
if (fetchPlansResponse.status === false) {
|
||||||
console.log("Error fetching plans: ", fetchPlansResponse.message);
|
console.log('Error fetching plans: ', fetchPlansResponse.message);
|
||||||
return res
|
return res
|
||||||
.status(400)
|
.status(400)
|
||||||
.send(`Error fetching subscriptions: ${fetchPlansResponse.message}`);
|
.send(`Error fetching subscriptions: ${fetchPlansResponse.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let plans = fetchPlansResponse.data.filter(
|
return res.status(200).send(fetchPlansResponse.data);
|
||||||
(plan) => plan_codes.indexOf(plan.plan_code) !== -1
|
|
||||||
);
|
|
||||||
return res.status(200).send(plans);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/subscription", async (req, res) => {
|
app.get('/subscription', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let { customer } = req.query;
|
let { customer } = req.query;
|
||||||
|
|
||||||
if (!customer) {
|
if (!customer) {
|
||||||
throw Error("Please include a valid customer ID");
|
throw Error('Please include a valid customer ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
let fetchSubscriptionsResponse = await paystack.subscription.list({
|
let fetchSubscriptionsResponse = await paystack.subscription.list({
|
||||||
@@ -48,7 +43,7 @@ app.get("/subscription", async (req, res) => {
|
|||||||
|
|
||||||
if (fetchSubscriptionsResponse.status === false) {
|
if (fetchSubscriptionsResponse.status === false) {
|
||||||
console.log(
|
console.log(
|
||||||
"Error fetching subscriptions: ",
|
'Error fetching subscriptions: ',
|
||||||
fetchSubscriptionsResponse.message
|
fetchSubscriptionsResponse.message
|
||||||
);
|
);
|
||||||
return res
|
return res
|
||||||
@@ -60,9 +55,8 @@ app.get("/subscription", async (req, res) => {
|
|||||||
|
|
||||||
let subscriptions = fetchSubscriptionsResponse.data.filter(
|
let subscriptions = fetchSubscriptionsResponse.data.filter(
|
||||||
(subscription) =>
|
(subscription) =>
|
||||||
(subscription.status === "active" ||
|
subscription.status === 'active' ||
|
||||||
subscription.status === "non-renewing") &&
|
subscription.status === 'non-renewing'
|
||||||
plan_codes.indexOf(subscription.plan.plan_code) !== -1
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(200).send(subscriptions);
|
return res.status(200).send(subscriptions);
|
||||||
@@ -72,13 +66,13 @@ app.get("/subscription", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/initialize-transaction-with-plan", async (req, res) => {
|
app.post('/initialize-transaction-with-plan', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let { email, amount, plan } = req.body;
|
let { email, amount, plan } = req.body;
|
||||||
|
|
||||||
if (!email || !amount || !plan) {
|
if (!email || !amount || !plan) {
|
||||||
throw Error(
|
throw Error(
|
||||||
"Please provide a valid customer email, amount to charge, and plan code"
|
'Please provide a valid customer email, amount to charge, and plan code'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,13 +80,13 @@ app.post("/initialize-transaction-with-plan", async (req, res) => {
|
|||||||
email,
|
email,
|
||||||
amount,
|
amount,
|
||||||
plan,
|
plan,
|
||||||
channels: ["card"],
|
channels: ['card'], // limiting the checkout to show card, as it's the only channel that subscriptions are currently available through
|
||||||
callback_url: "http://localhost:2426/account.html",
|
callback_url: 'http://localhost:5000/account.html',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (initializeTransactionResponse.status === false) {
|
if (initializeTransactionResponse.status === false) {
|
||||||
return console.log(
|
return console.log(
|
||||||
"Error initializing transaction: ",
|
'Error initializing transaction: ',
|
||||||
initializeTransactionResponse.message
|
initializeTransactionResponse.message
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -103,12 +97,12 @@ app.post("/initialize-transaction-with-plan", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/create-subscription", async (req, res) => {
|
app.post('/create-subscription', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let { customer, plan, authorization, start_date } = req.body;
|
let { customer, plan, authorization, start_date } = req.body;
|
||||||
|
|
||||||
if (!customer || !plan) {
|
if (!customer || !plan) {
|
||||||
throw Error("Please provide a valid customer code and plan ID");
|
throw Error('Please provide a valid customer code and plan ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
let createSubscriptionResponse = await paystack.subscription.create({
|
let createSubscriptionResponse = await paystack.subscription.create({
|
||||||
@@ -120,7 +114,7 @@ app.post("/create-subscription", async (req, res) => {
|
|||||||
|
|
||||||
if (createSubscriptionResponse.status === false) {
|
if (createSubscriptionResponse.status === false) {
|
||||||
return console.log(
|
return console.log(
|
||||||
"Error creating subscription: ",
|
'Error creating subscription: ',
|
||||||
createSubscriptionResponse.message
|
createSubscriptionResponse.message
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -131,13 +125,13 @@ app.post("/create-subscription", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/cancel-subscription", async (req, res) => {
|
app.post('/cancel-subscription', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let { code, token } = req.body;
|
let { code, token } = req.body;
|
||||||
|
|
||||||
if (!code || !token) {
|
if (!code || !token) {
|
||||||
throw Error(
|
throw Error(
|
||||||
"Please provide a valid customer code and subscription token"
|
'Please provide a valid customer code and subscription token'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,25 +140,13 @@ app.post("/cancel-subscription", async (req, res) => {
|
|||||||
token,
|
token,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (disableSubscriptionResponse.status === false) {
|
return res.send('Subscription successfully disabled');
|
||||||
console.log(
|
|
||||||
"Error disabling subscriptions: ",
|
|
||||||
disableSubscriptionResponse.message
|
|
||||||
);
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.send(
|
|
||||||
`Error disabling subscriptions: ${disableSubscriptionResponse.message}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.send("Subscription successfully disabled");
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).send(error);
|
return res.status(400).send(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/update-payment-method", async (req, res) => {
|
app.get('/update-payment-method', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { subscription_code } = req.query;
|
const { subscription_code } = req.query;
|
||||||
const manageSubscriptionLinkResponse =
|
const manageSubscriptionLinkResponse =
|
||||||
@@ -172,6 +154,7 @@ app.get("/update-payment-method", async (req, res) => {
|
|||||||
code: subscription_code,
|
code: subscription_code,
|
||||||
});
|
});
|
||||||
if (manageSubscriptionLinkResponse.status === false) {
|
if (manageSubscriptionLinkResponse.status === false) {
|
||||||
|
console.log(manageSubscriptionLinkResponse.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
let manageSubscriptionLink = manageSubscriptionLinkResponse.data.link;
|
let manageSubscriptionLink = manageSubscriptionLinkResponse.data.link;
|
||||||
@@ -181,12 +164,12 @@ app.get("/update-payment-method", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/create-customer", async (req, res) => {
|
app.post('/create-customer', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let { email } = req.body;
|
let { email } = req.body;
|
||||||
|
|
||||||
if (!email) {
|
if (!email) {
|
||||||
throw Error("Please include a valid email address");
|
throw Error('Please include a valid email address');
|
||||||
}
|
}
|
||||||
|
|
||||||
let createCustomerResponse = await paystack.customer.create({
|
let createCustomerResponse = await paystack.customer.create({
|
||||||
@@ -194,14 +177,15 @@ app.post("/create-customer", async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (createCustomerResponse.status === false) {
|
if (createCustomerResponse.status === false) {
|
||||||
console.log("Error creating customer: ", createCustomerResponse.message);
|
console.log('Error creating customer: ', createCustomerResponse.message);
|
||||||
return res
|
return res
|
||||||
.status(400)
|
.status(400)
|
||||||
.send(`Error creating customer: ${createCustomerResponse.message}`);
|
.send(`Error creating customer: ${createCustomerResponse.message}`);
|
||||||
}
|
}
|
||||||
let customer = createCustomerResponse.data;
|
let customer = createCustomerResponse.data;
|
||||||
|
|
||||||
// This is where you would save your customer to your DB. Here, we're mocking that by just storing the customer_code in a cookie
|
// This is where you would save your customer to your DB. Here, we're mocking that by just storing the customer_code in a cookie
|
||||||
res.cookie("customer", customer.customer_code);
|
res.cookie('customer', customer.customer_code);
|
||||||
return res.status(200).send(customer);
|
return res.status(200).send(customer);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@@ -210,27 +194,27 @@ app.post("/create-customer", async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Handle subscription events sent by Paystack
|
// Handle subscription events sent by Paystack
|
||||||
app.post("/webhook", async (req, res) => {
|
app.post('/webhook', async (req, res) => {
|
||||||
const hash = crypto
|
const hash = crypto
|
||||||
.createHmac("sha512", secret)
|
.createHmac('sha512', secret)
|
||||||
.update(JSON.stringify(req.body))
|
.update(JSON.stringify(req.body))
|
||||||
.digest("hex");
|
.digest('hex');
|
||||||
if (hash == req.headers["x-paystack-signature"]) {
|
if (hash == req.headers['x-paystack-signature']) {
|
||||||
const webhook = req.body;
|
const webhook = req.body;
|
||||||
res.status(200).send("Webhook received");
|
res.status(200).send('Webhook received');
|
||||||
|
|
||||||
switch (webhook.event) {
|
switch (webhook.event) {
|
||||||
case "subscription.create":
|
case 'subscription.create':
|
||||||
case "charge.success":
|
case 'charge.success':
|
||||||
case "invoice.update":
|
case 'invoice.update':
|
||||||
case "invoice.payment_failed":
|
case 'invoice.payment_failed':
|
||||||
case "subscription.not_renew":
|
case 'subscription.not_renew':
|
||||||
case "subscription.disable":
|
case 'subscription.disable':
|
||||||
case "subscription.expiring_cards":
|
case 'subscription.expiring_cards':
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(process.env.PORT, () => {
|
||||||
console.log(`Listening on port ${port}`);
|
console.log(`App running at http://localhost:${process.env.PORT}`);
|
||||||
});
|
});
|
||||||
Generated
-1043
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "server",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "server.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
|
||||||
"start": "node server.js",
|
|
||||||
"dev": "nodemon server.js"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"@paystack/paystack-sdk": "^1.0.0-beta.6",
|
|
||||||
"dotenv": "^16.0.1",
|
|
||||||
"express": "^4.18.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user