Razorpay subscription handler not sending response.razorpay_subcription_id and response.razorpay_signature - node.js

I am trying to implement a model in which if a user pays for the first time he is registered with the subscription according to plan he selects.
I am using ReactJs as forntend and NodeJs as backend.
There are 2 issues that I am currently facing -
Not getting razorpay_subscription_id and razorpay_signature -
This is the Nodejs code for creating a subscription and returning subscriptionId for further process.
const plans = await instance.plans.all();
let i;
for (i = 0; i < plans.count; i++) {
if (plans.items[i].item.name === "Test plan - Weekly") break;
}
const planId = plans.items[i].id;
const subscriptionData = {
plan_id: planId,
total_count: 1,
quantity: 1,
customer_notify: 1,
};
const response = await instance.subscriptions.create(subscriptionData);
res.send(response.id);
This is my react code to open razorpay for payment. When this opens I do get an error in console, which is serviceworker must be a dictionary in your web app manifest.
Note - I have replaced key below due to security reasons.
axios.get("http://localhost:5000/razorpay").then((subscriptionId) => {
var options = {
key: "Test_Key",
subscription_id: subscriptionId,
name: "Consuma",
description: "Monthly Test Plan",
handler: function (response) {
console.log(response);
},
};
var razorpay = new window.Razorpay(options);
razorpay.open();
razorpay.on("payment.failed", function (response) {
alert(response.error.code);
alert(response.error.description);
alert(response.error.source);
alert(response.error.step);
alert(response.error.reason);
alert(response.error.metadata.order_id);
alert(response.error.metadata.payment_id);
});
});
I should expect razorpay_subscription_id and razorpay_signature for verification, but those fields are missing.
Below is the response that I get.
checkout_logo: "https://cdn.razorpay.com/logo.png"
custom_branding: false
org_logo: ""
org_name: "Razorpay Software Private Ltd"
razorpay_payment_id: "pay_HS0u4wIhrQavw
Payment not being captured and not considered as subscription payment
The plan that I used above is of Rs. 699 to be charged weekly, but while paying the amount I am only asked to pay Rs. 1. According to Razorpay documentation this rs 1 is an authorization from the user to subscribe to the plan and once this is successful, the plan amount will be deducted from users account as per the plan. But nothing such happens. Also, in the Razorpay dashboard this payment is considered as authorized and not as captured.

So, the first issue was an error in code. I wasn't sending a correct subscription id and due to that I wasn't receiving any expected response.
As far as 'serviceworker' error is considered I received following response fro razorpay team.

Related

Fail to join the meeting (ZOOM-SDK)

I’m new to Zoom. what I’m trying to do is to integrate zoom meeting into my ReactJS app.
first of all, I tried to use the zoom sample web app to check how it works.
so I cloned this project from
GitHub - zoom/sample-app-web: Zoom Meeting SDK for Web Sample App
following the readme instruction
I created a new app in the marketplace.zoom to get needed credentials API__key API_secrect
also, I used this function to create a new signature
function generateSignature(apiKey, apiSecret, meetingNumber, role) {
// Prevent time sync issue between client signature generation and Zoom
const timestamp = new Date().getTime() - 30000
const msg = Buffer.from(apiKey + meetingNumber + timestamp + role).toString('base64')
const hash = crypto.createHmac('sha256', apiSecret).update(msg).digest('base64')
const signature = Buffer.from(apiKey, meetingNumber, timestamp, role, hash).toString('base64')
return signature
}
but when I tried to join a meeting
I got this error
{
"type": "JOIN_MEETING_FAILED",
"reason": "Fail to join the meeting.",
"errorCode": 200
}
Can you please help me out?

The specified Checkout Session could not be found

Goal: Create a successful (test) Checkout Session using Stripe's API for checkout.
[the link for their tutorial on Checkout here: https://github.com/stripe-samples/checkout-one-time-payments]
I'm creating a checkout session using my UI & building the checkout session with the data supplied to the backend web service using the following code:
var options = new Stripe.Checkout.SessionCreateOptions
{
PaymentMethodTypes = new List<string>
{
"card",
},
LineItems = stripeCartLineItems,
Mode = "payment",
SuccessUrl = "https://" + HostName + "/Stripe/OrderPlaced",
CancelUrl = "https://example.com/cancel",
};
var requestOptions = new RequestOptions
{
StripeAccount = stripeConnectedAccountId,
ApiKey = StripeConfiguration.ApiKey
};
var service = new Stripe.Checkout.SessionService();
Stripe.Checkout.Session session = service.Create(options, requestOptions);
return Json(new { sessionId = session.Id });
As you can see, I receive acknowledgment back from Stripe's API with a valid checkout session id:
Logs on Stripe's Dashboard confirm a successful checkout session:
However, I keep getting this error message:
The API keys have already been refreshed and placed appropriately. That's not the issue... Loading up the test Checkout page is failing. My logs in Stripe's dashboard say this:
The Javascript call which initiates the redirect to Stripe's checkout experience is copied straight from their tutorial (pasted above). That code looks like this:
checkoutButton.addEventListener('click', function () {
$.ajax({
url: "/Stripe/CreateCheckoutSession",
method: "POST",
data: { stripeConnectedAccountId: stripeConnectedAccountId, cartLineItems: scope.cartLineItems },
}).done(function (resp) {
stripe.redirectToCheckout({
sessionId: resp.sessionId
}).then(function (result) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer
// using `result.error.message`.
alert(result.error.message);
});
})
After going to: https://stripe.com/docs/error-codes/resource-missing. The docs says this for that specific error code: "The ID provided is not valid. Either the resource does not exist, or an ID for a different resource has been provided."
Ok Stripe. Sure sure. You made this API - I'll listen. However, according to your docs, Intellisense, & your sample code... my code is correct and I used the session.Id provided by the response object YOU sent me after initiating a Checkout Session:
I have no clue how to proceed.
Any ideas are appreciated.
If you have already verified the session and keys from server and stripe,
Please check the stripe key used in your client side. The public key used to initialise the stripe in both client & server should be same.
Check the logs in client side to make sure that the key is same.

PDS2 Stripe Success Webhook and other issues

This is in danger of being TLDR - so my question is: On successful payment - stripes sends a "success" payload to my success webhook. Looking through the payload, I am unable to see anything which I can use to find which payment was successful. Should I be saving something from my stripe session to my pending payment?
Greater detail:
To comply with PSD2, I've had to rejig our stripe payments. We support a few different payment options, which has affected how I go about the process.
Before, with stripe, we'd get a token - send it client side... payment made - order saved to DB.. job done.
Now, the flow is reversed...
I have a "Stripe" button - customer clicks on it. A POST is made to the server. On the server I grab the customers cart and create an order with a payment status of pending.
I then create a stripe session - and return the stripe session ID to the client (code is abridged)
//creates order and returns Order ID
const orderid = await createOrder(cart);
const stripeSession = await stripe.checkout.sessions.create({
customer_email: request.payload.billingEmail,
payment_method_types: ["card"],
line_items: [
{
name: "###",
description: "###" + orderid,
amount: cart.total.total,
currency: cart.total.currency,
quantity: 1
}
],
success_url: "###" + orderid,
cancel_url: "###/checkout"
});
return {
stripeSessionID: stripeSession.id
};
and on my client I have this method method to post to the server and automatically redirect to external stripe checkout page:
stripeCheckout: function () {
...
axios.post('/pay/get-stripe-session', data)
.then(function (response) {
var checkoutSessionID = response.data.stripeSessionID
stripe.redirectToCheckout({
sessionId: checkoutSessionID
}) ...
Upon succesful payment, stripe sends a "success" payload to my success webhook. I check the stripe signature - and receive the message... this all works... however, I can't see any data in the payload that I can use to match the payment with the order (in order to update the orders payment status).
When I create my stripe session is there anything from it that I can use?
** Edit ** -
When creating a stripe session, one can pass client_reference_id. into the create session method as a unique key. However, stripes success webhook does NOT return this key in its payload - so this cannot be used to reconcile a successful payment with an order.
We have our own customer accounts system. Under the old API we could set up a charge thus:
const charge = await stripe.charges.create({
amount: total,
currency: currency,
source: token, // obtained with Stripe.js
description: orderid
})
And the description would appear in stripes dashboard making it easy to find a payment (to make a refund or whatever). We don't use Stripes 'customers'. We store orders, and customers in our system (stripe is not a customer management system). If the customer is logged in when they check out, we link them to their order. Guest orders aren't linked to anyone.
However, under the new api where you have to create a stripeSession every session creates a customer in stripes dashboard. Can we prevent this?
Also, there is no way to add a description to the overall session / charge like you could with the old charge api - so in Stripes Payments dashboard, we end up with unusable junk for each payment description...
Does anyone know how to fix this? I hope stripe aren't having to sacrifice their wonderful developer experince to comply with PDS2
When you create the CheckoutSession, you can pass it a client_reference_id. That value will be present on the object later for you to reference an order in your own systems.
Solved it:
The trick is to set meta-data on your stripe session:
const stripeSession = await stripe.checkout.sessions.create({
customer_email: billingEmail,
client_reference_id: orderid,
payment_method_types: ["card"],
line_items: [
{
name: "My charge",
description: "Lorem ipsum",
amount: total,
currency: currency,
quantity: 1
}
],
payment_intent_data: {
description: `orderID: ${orderid}`,
metadata: {
orderid : orderid
}
},
success_url: "https://example.com/thankyou/",
cancel_url: "https://example.com/checkout"
});
The metadata is returned in the charge.success event (webhook). Using this metadata, I am able to find the order in my database and update it. In our case, I take the transaction.id, card type and last 4 card digits from the charge.success event and update the payment status to paid.
If you don't need this information - you could simply set your webhook to receive the checkout.session.complete event as that contains the client_reference_id (and I believe is stripes preferred event to confirm a transaction)
Because we're not using Customers accounts inside Stripe, I also remove the customer from stripe:
// Delete the customer from Stripes Dashboard (we don't use it - its clutter)
const customerID = event.data.object.customer
stripe.customers.del(
customerID,
function(err, confirmation) {
// asynchronously called
}
);
And thats basically it. Use the meta - it seems to be sent on every event.

Inconsistent - "The project id used to call the Google Play Developer API has not been linked in the Google Play Developer Console."

So here's the thing - I have a node.js backend server for my Android App. I am using the Google Play billing library, and using the backend to verify the purchase as google Docs recommend.
Now, all the other answers out there regarding this error seem to refer to a consistent problem.
My backend SOMETIMES verifies, and SOMETIMES comes back with this as an error, indicating that in fact, my service account IS linked (as shows up in my consoles).
I tried two different 3rd party libraries, and I have the same issue. Sometimes one will respond with verification success, while the other will say my account is not linked. Sometimes they are both negative, sometimes both positive.
It seems inconsistent.
var platform = 'google';
var payment = {
receipt: purchaseToken, // always required ... this is google play purchaseToken
productId: subID, // my subscription sku id
packageName: 'com.xxxxxx', // my package name
keyObject: key, // my JSON file
subscription: true, // optional, if google play subscription
};
var promise2 = iap.verifyPayment(platform, payment, function (error, response) {
/* your code */
if (error) {
console.log('error with iap, ' , error);
return true;
} else {
console.log('success with iap, response is: ', response);
return true;
}
});
I also tried with a different library, got same results:
var receipt = {
packageName: "com.xxxx",
productId: subID, // sku subscription id
purchaseToken: purchaseToken // my purchase token
};
var promise = verifier.verifySub(receipt, function cb(err, response) {
if (err) {
console.log('within err, was there a response? : ', response);
console.log('there was an error validating the subscription: ', err);
//console.log(err);
return true;
} else {
console.log('sucessfully validated the subscription');
// More Subscription info available in “response”
console.log('response is: ', response );
return true;
}
});
// return promises later.
Any else experience this issue?
TLDR; Create a new product ID.
I eventually found the answer. The problem was not with my code, or with permissions in the Google Developer Console OR the Google Play Console. Everything was set up correctly except for one thing.
Previously, before setting up Test License Accounts in Google Play Console, I had made an actual Subscription purchase with real money on my productID "X".
Then, after adding the same google account that bought the subscription as a test user, I continued to test results on the same subscription, productID "X".
Even though I had cancelled the REAL purchase, the actual expiration date was not for another month.
Therefore, I believe sometimes Google was getting confused when I would buy/cancel the purchase - confusing the test subscription with the real subscription.
Creating a new Product ID, and only using that, solved my problem, and purchases are verified consistently.

How do i update a user's subscription date using stripe webhooks?

I'm building a subscription plan in node.js, I read the documentation about how to subscribe a user to a plan, and it was successful.
Stripe's doc states that I have to store an active_until field in the database. It says when something changes use webhook, i know that webhook is like an event.
The real questions are
1) how do I do a repeat the bill every month using active_until?
2) How do I use webhook, I really don't understand.
Here's the code so far.
var User = new mongoose.Schema({
email: String,
stripe: {
customerId: String,
plan: String
}
});
//payment route
router.post('/billing/:plan_name', function(req, res, next) {
var plan = req.params.plan_name;
var stripeToken = req.body.stripeToken;
console.log(stripeToken);
if (!stripeToken) {
req.flash('errors', { msg: 'Please provide a valid card.' });
return res.redirect('/awesome');
}
User.findById({ _id: req.user._id}, function(err, user) {
if (err) return next(err);
stripe.customers.create({
source: stripeToken, // obtained with Stripe.js
plan: plan,
email: user.email
}).then(function(customer) {
user.stripe.plan = customer.plan;
user.stripe.customerId = customer.id;
console.log(customer);
user.save(function(err) {
console.log("Success");
if (err) return next(err);
return next(null);
});
}).catch(function(err) {
// Deal with an error
});
return res.redirect('/');
});
});
How do i Implement the active_until timestamps and the webhook event?
active_until is just the name of a database column that you can create on your users table to store the timestamp representing when the user's account expires. The name of the column doesn't matter. You can use any name you want.
In order to verify if a user's subscription is current, Stripe is suggesting that you use logic like this:
If today's date <= user.active_until
allow them access
Else
show them an account expired message
The webhook is a request that Stripe's servers make to your server to tell you that something has happened. In this case, the event you are most interested in is invoice.payment_succeeded.
Your webhook will include logic like this:
if event type is "invoice.payment_succeeded"
then update user.active_until to be equal to today's date + 1 month
You will also want to respond to other events in case the payment fails, etc.
You don't need to repeat the bill every month. Stripe will do it for you.
Once you subscribed your user to a plan, stripe will charge him till the paid period is over.
Every time stripe charges a customer it will generate a webhook, that is a request on your server to some specified URL. Stripe can generate different webhooks for different reasons.
For example when customer gets charged by subscription, Stripe will send you info about payment.
router.post('/billing/catch_paid_invoice', function(req, res) {
// Here you parse JSON data from Stripe
}):
I don't have access to Stripe settings right now, but a remember setting urls for webhooks manually.
Select your account name > Account Settings > Webhooks
active_until is just a reminder that customer is still active and have paid services in your system. It needs to be updated when getting webhooks.
Stripe docs are really good, so go through them one more time.
https://stripe.com/docs/guides/subscriptions

Resources