i'm implementing razorpay payment gateway in my React.js app with backend nodejs.
here frontend.jsx
razorpayHandler = () =>{
const payment_amount = this.props.TotalPrice;
const backend_url = 'https://25234399bb.ngrok.io';
const self = this;
const options = {
key: config.RAZOR_PAY_KEY,
amount: payment_amount * 100,
name: 'StanPlus',
description: 'pay your ambulance fare',
handler(response) {
const paymentId = response.razorpay_payment_id;
const url = backend_url+'/razorpay/'+paymentId+'/'+payment_amount+'/'+self.id;
console.log(paymentId)
// Using my server endpoints to capture the payment
fetch(url, {
method: 'get',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
}
})
.then(resp => resp.json())
.then(function (data) {
console.log(data)
})
.catch(function (error) {
console.log('Request failed', error);
});
},
theme: {
color: '#40A9FF',
},
};
const rzp1 = new window.Razorpay(options);
rzp1.open();
}
backend.js(nodejs)
var express = require('express');
var router = express.Router();
var config = require('../config');
const Razorpay = require('razorpay');
const instance = new Razorpay({
key_id: config.razorpay_live_key,
key_secret: config.razorpay_live_secret,
});
router.get('/:payment_id/:amount/:BID',function(req,res,next){
const {payment_id } = req.params;
const {BID} = req.params;
const amount = Number(req.params.amount*100);
instance.payments.capture(payment_id, amount).then((data) => {
data.Bid = BID;
res.json(data);
}).catch((error) => {
res.json(error);
});
})
module.exports = router;
it showing me error
"statusCode":400,"error":{"code":"BAD_REQUEST_ERROR","description":"The id provided does not exist"
but if the same code if do process using test key its getting successfully completed but it is not working with live api.
here i'm passing an extra parameter to the backend which required for us but if removed that parameter then also it is not working.but with parameter it is working with test api.
when we send request to backend it is generating id and sending to backend also but still it showing The id provided does not exist.
if you are using test mode then just remove order_id parameter from json object.
I also faced this error a week ago. This error arrived when we changed the test keys to the production keys for final payment to work.
So I faced this issue The id provided does not exist because of the mismatch of Razorpay Keys on the frontend and backend side(node.js side.)
So make sure you have the same client key and secret of the production environment on both backend and frontend side.
Let me know in comments if it still is not resolved.
For Test Remove the OrderId from your options json data.
For Live mode Pass the autogenerated Orderid From the user Control.
Removing order_id is not good practice we should follow documentation.
To get order_id in React you have to first create a order in your backend eg(node.js). follow this steps to get order_id from Razorpay.
Step - 1
var instance = new Razorpay({ key_id: 'YOUR_KEY_ID', key_secret: 'YOUR_KEY_SECRET'})
this will initiate new Razorpay object.
Step - 2
MyOrder = instance.orders.create({amount, currency, receipt, notes})
this will create an order for you and then you have access to order_id. You can log MyOrder to see more available attributes or just console.log(MyOrder.id) to get order_id
and finally you have to pass your order_id in your case you have to pass order_id in options.
Note : You can access order id like this MyOrder.id
for more information check official doc.
you can find Razorpay SDKs for various Platform here
If you are using for payments, than remove order_id from options JSON value.
var options = {
"key": "xxxxxxxxxxxxxxx", // Enter the Key ID generated from the Dashboard
"amount": "50000", // Amount is in currency subunits. Default currency is INR. Hence, 50000 refers to 50000 paise
"currency": "INR",
"name": "Acme Corp",
"description": "Test Transaction",
"image": "https://example.com/your_logo",
// "order_id": "order_9A33XWu170gUtm", //This is a sample Order ID. Pass the `id` obtained in the response of Step 1
"handler": function (response){
alert(response.razorpay_payment_id);
alert(response.razorpay_order_id);
alert(response.razorpay_signature)
},
"prefill": {
"name": "Gaurav Kumar",
"email": "gaurav.kumar#example.com",
"contact": "9999999999"
},
"notes": {
"address": "Razorpay Corporate Office"
},
"theme": {
"color": "#3399cc"
}
};
This error happens when you pass an incorrect order_id to trigger the payment modal. Basically an order_id that does not belong to your razorpay account, or an invalid one.
Example: if you generated an order_id with one set of credentials and use another set of credentials afterwards, this issue can happen.
I too faced the same problem while integrating Razorpay for subscription payments
Initially, I passed order_id in the options param, which yielded the error -
{
"code": "BAD_REQUEST_ERROR",
"description": "The id provided does not exist",
"source": "business",
"step": "payment_initiation",
"reason": "input_validation_failed",
"metadata": {}
}
Hence replaced order_id with subscription_id.
Works now!
Check for the rp_type,
for subscription pass options["subscription_id"],
for orders pass options["order_id"]
Related
I using node server and I need birthday and gender but I only get name, email,
and photo. I using this (#react-oauth/google) library in frontend. I using react in
the frontend. When I send api request from frontend I get only name, email, and
photo. And here is the backend code. So please I need the solution of my
problem.
const express = require('express');
const app = express();
const { OAuth2Client } = require('google-auth-library');
const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);
const users = [];
function upsert(array, item) {
const i = array.findIndex((_item) => _item.email === item.email);
if (i > -1) array[i] = item;
else array.push(item);
}
app.post('/api/google-login', async (req, res) => {
const { token } = req.body;
const ticket = await client.verifyIdToken({
idToken: token,
audience: process.env.GOOGLE_CLIENT_ID,
});
const { name, email, picture } = ticket.getPayload();
upsert(users, { name, email, picture });
console.log(ticket.getPayload());
res.status(201);
res.json({ name, email, picture });
});
app.listen(process.env.PORT || 5000, () => {
console.log(
`Server is ready at http://localhost:${process.env.PORT || 5000}`
);
});
I'm the creator of #react-oauth
I'm thrilled that you gave it a try.
Actually, I didn't try to get user age before 😅, But I just found something that will guide you in the right direction I wish.
Any extra information required from the user regardless of email, name, and pic (public ones) we need the permission from them
you need to add scope https://www.googleapis.com/auth/user.gender.read to read user's gender and same for birthday
All scopes available here https://developers.google.com/identity/protocols/oauth2/scopes | your need is under People API
Enable Google People API https://console.cloud.google.com/apis/library/browse?project=ferrous-terrain-348520&q=people
Generate API Key we will need it later when requesting from google people API
you can find people GET API here, I figured first request from there sidebar playground and network from dev tools.
I will give you an example I tried on the client, But I believe you can achieve this also on the server with google-apis-node
when using in your App, make the two requests with Promise.all, It's just like that for demo
Add you API_KEY
specify fields that you need to get
const googleLogin = useGoogleLogin({
onSuccess: async tokenResponse => {
console.log(tokenResponse);
const userInfo = await axios
.get('https://www.googleapis.com/oauth2/v3/userinfo', {
headers: { Authorization: `Bearer ${tokenResponse.access_token}` },
})
.then(res => res.data);
const gender = await axios
.get(
`https://people.googleapis.com/v1/people/me?key=${<YOU_API_KEY}&personFields=genders`,
{
headers: { Authorization: `Bearer ${tokenResponse.access_token}` },
},
)
.then(res => res.data);
console.log(userInfo, gender);
},
scope: 'https://www.googleapis.com/auth/user.gender.read',
});
I'm sorry but to specify scopes we need to use google authorization flow that can't be used with the personalized button, But I believe that you can do fetching the user info like you are doing and same for age. you can replace /me to /<USER_ID>
and your frontend can use the personalized button as it is.
I just found that you can do it without API key
https://content-people.googleapis.com/v1/people/<USER_ID>?personFields=genders
I think you got the idea 😄
You can check their documentation
They do not return gender and birthdate. Here is an example of a full response containing the information that you can use (from the documentation link above)
{
// These six fields are included in all Google ID Tokens.
"iss": "https://accounts.google.com",
"sub": "110169484474386276334",
"azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
"aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
"iat": "1433978353",
"exp": "1433981953",
// These seven fields are only included when the user has granted the "profile" and
// "email" OAuth scopes to the application.
"email": "testuser#gmail.com",
"email_verified": "true",
"name" : "Test User",
"picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
"given_name": "Test",
"family_name": "User",
"locale": "en"
}
I'm trying to build an App which allows the customer to download a custom document after his order (so, the product I'm selling it's a digital custom document in pdf).
I'm trying to build that using React for the frontend, Node and Express for the backend, and PayPal Express Checkout (full-stack implementation) as payment.
What is not clear to me is what steps I should take to process an order.
I'm a this point:
Once customer clicks on PayPal button on client side it starts a call on http://localhost/api/paypal/orders endpoint which create the order on the Paypal side and return the PayPal order ID (e.g. id12345)
After the customer approves the payment on the PayPal popup, the client starts a call on http://localhost/api/paypal/orders/id12345/capture endpoint
then? What other endpoints should I crete on the server and what they should return? Maybe... 1 for save the actual store order on my MongoDB and the transaction details, 1 for create the invoice for the order, 1 for allowing the product download ???
Could you please clarify what steps I need to take, what are the endpoints I should create, and what each endpoints should return?
Maybe something like this?
You're trying to do too many things in too many routes. just create a route called something like process-order then you could have an async controller of that route which would contain separate functions for
Storing the order details in mongodb.
Create an invoice
Send a token that allows access to download page.
first , just await the function to complete then call the next.
exports.processOrder = async (req, res, next) => {
try {
const newOrder = await Order.create({
order: req.params.id,
details: req.body.details
})
const createInvoice = () => {
return newOrder._id;
}
const invoice = createInvoice();
const token = jwt.sign(
{
invoiceId = newOrder._id,
},
process.env.JWT_SECRET,
{
expiresIn: '24h'
}
);
return res.status(200).json({status: 'success', message: 'you have 24 hours to download your digital goods', token})
} catch (error) {
res.status(500).send(error)
}
}
This is a very basic idea, but basically store all of your info in one controller, then send a token with the id of the invoice, then when they go to download the book you would have a route where you verify the token. If it succeeds then the book is sent. like this:
app.use(
'/book-download',
expressJwt({ secret: process.env.JWT_SECRET, algorithms: ['HS256'] })
);
app.get('/book-download/success', async (req, res) => {
try{
const invoiceId = req.user.invoiceId;
const invoice = await Invoice.find({_id: invoiceId})
if (invoice) {
return res.status(200).json({status: 'success', message: 'congratulations on your new download', data: {E-book})
} else {
return.res.status(404).json({status: 'fail', message: 'could not find an invoice with that ID'})
} catch (error) {
return res.send(error)
}
});
You can choose to send the pdf via express, or you can allow them to enter a certain part of the website if the return is valid. There you go, that's an idea.
In Express check out, you need to define success / cancel handler
Ref here : https://www.section.io/engineering-education/nodejs-paypal-checkout/
In the success handler, based on the returned URI => you will get a Payer ID and payment ID. Based on that retrieve the transactio information (that internally contains yours order ID). Update your Order id as scucess / cancelled based on the paypal response.
app.get('/success', (req, res) => {
const payerId = req.query.PayerID;
const paymentId = req.query.paymentId;
const execute_payment_json = {
"payer_id": payerId,
"transactions": [{
"amount": {
"currency": "USD",
"total": "25.00"
}
}]
};
// Obtains the transaction details from paypal
paypal.payment.execute(paymentId, execute_payment_json, function (error, payment) {
//When error occurs when due to non-existent transaction, throw an error else log the transaction details in the console then send a Success string reposponse to the user.
if (error) {
console.log(error.response);
throw error;
} else {
console.log(JSON.stringify(payment));
res.send('Success');
}
});
});
Update
I'm able to get my original code, and the suggestions as well working when running it in isolation. However, what I need to do is call it from within a Firebase onRequest or onCall function. When this code gets wrapped by these, the malformed headers and request for authorization are still an issue. We use many other APIs this way so it's puzzling why the Clarifiai API is having these issues. Any suggestions on using it with Firebase?
Original
New to Clarifai and having some authentication issues while attempting to retrieve model outputs from the Food Model.
I've tried two different keys:
API key generated from an app I created in the Portal
API key - the Personal Access Token I generated for myself
In both cases I encounter an Empty or malformed authorization header response.
{
"status":{
"code":11102,
"description":"Invalid request",
"details":"Empty or malformed authorization header. Please provide an API key or session token.",
"req_id":"xyzreasdfasdfasdfasdfasf"
},
"outputs":[
]
}
I've following the following articles to piece together this code. This is running in a Node 10 environment.
Initialization
Food Model
Prediction
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key xyzKey");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
resolve(JSON.stringify(response));
}
);
});
}
Update: There was an issue in versions prior to 7.0.2 where, if you had another library using #grpc/grpc-js with a different version, the grpc.Metadata object wasn't necessarily constructed from the library version that clarifai-grpc-nodejs was using.
To fix the issue, update the clarifai-grpc-nodejs library, and require the grpc object like this:
const {ClarifaiStub, grpc} = require("clarifai-nodejs-grpc");
Previously, the grpc object was imported directly from #grpc/grpc-js, which was the source of the problem.
There are two ways of authenticating to the Clarifai API:
with an API key, which is application-specific, meaning that an API key is attached to an application and can only do operations inside that application,
with a Personal Access Token (PAT), which is user-specific, which means you can assess / manipulate / do operations on all the applications the user owns / has access to (and also create/update/delete applications themselves).
When using a PAT, you have to specify, in your request data, which application you are targeting. With an API key this is not needed.
I've tested your example (using Node 12, though it should work in 10 as well) with a valid API key and it works fina (after putting it into an async function). Here's a full runnable example (replace YOUR_API_KEY with your valid API key).
function predict() {
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key YOUR_API_KEY");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
resolve(JSON.stringify(response));
}
);
});
}
async function main() {
const response = await predict();
console.log(response);
}
main();
If you want to use a PAT in the above example, two things must change. Firstly, replace the API key with a PAT:
...
metadata.set("authorization", "Key YOUR_PAT");
...
To the method request object, add the application ID.
...
stub.PostModelOutputs(
{
user_app_id: {
user_id: "me", // The literal "me" resolves to your user ID.
app_id: "YOUR_APPLICATION_ID"
},
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
...
Make sure that you have respected the format to pass the key in your code as such:
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {YOUR_CLARIFAI_API_KEY}");
Make sure that "Key" is present.
Let me know.
EDIT: So looks like Firebase doesn't support custom headers. This is likely impacting the 'Authorization' header. At least this is my best guess. See the comments in the following ticket.
Firebase hosting custom headers not working
The following code works for me:
{
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {APP API KEY}");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
console.log(JSON.stringify(response));
resolve(JSON.stringify(response));
}
);
});
}
There was a missing { although I'm not sure if that is what is reflected in the actual code you are running. I'm using in this case an APP API Key (when you create an App, there will be an API Key on the Application Details page.
It sounds like you might be using a Personal Access Token instead, which can be used like this:
{
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {Personal Access Token}"); // Sounds like you've made the personal access token correctly - go into settings, then authentication, then create one. Make sure it has proper permissions (I believe all by default).
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
user_app_id: {
user_id: "{USER ID}", // I used my actual ID, I did not put 'me'. You can find this under your profile.
app_id: "{APP NAME}" // This is the app ID found in the upper left corner of the app after it is created - not the API Key. This is generally what you named the app when you created it.
},
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
console.log(JSON.stringify(response));
resolve(JSON.stringify(response));
}
);
});
}
Make sure to fill out the: {Personal Access Token}, {USER ID} and {APP NAME}. I used my actual user id (found in the profile), and the app name is not the API Key for the app, but the name in the upper left corner when you're on the Application details page. This call worked for me.
Im trying to create a classroom using googles classroom API. Whenever run the classroom.create function I always receive the same error message. I'm using the JSON format from their docs but I just can't get it to work. I think I must be missing something.
This is the function:
async function listCourses(auth) {
const classroom = google.classroom({ version: 'v1', auth });
//Read data from JSON
let data = fs.readFileSync("class.json");
let course = JSON.parse(data);
//Try and create course
try {
const res = await classroom.courses.create(course);
console.log(res.data);
}
catch (error) {
console.log(error)
}
//List all current courses
classroom.courses.list({
pageSize: 10,
}, (err, res) => {
if (err) return console.error('The API returned an error: ' + err);
const courses = res.data.courses;
if (courses && courses.length) {
console.log('Courses:');
courses.forEach((course) => {
console.log(`${course.name} (${course.id})`);
});
} else {
console.log('No courses found.');
}
});
}
This is the JSON:
{
"id": "157942918368",
"name": "English - 9Y",
"section": "Period 2",
"ownerId": "me",
"courseState": "ACTIVE"
}
This is the error message:
code: 400,
errors: [
{
message: `Invalid JSON payload received. Unknown name "name": Cannot bind query parameter. Field 'name' could not be found in request message.\n` +
`Invalid JSON payload received. Unknown name "ownerId": Cannot bind query parameter. Field 'ownerId' could not be found in request message.\n` +
`Invalid JSON payload received. Unknown name "courseState": Cannot bind query parameter. Field 'courseState' could not be found in request message.\n` +
`Invalid JSON payload received. Unknown name "id": Cannot bind query parameter. Field 'id' could not be found in request message.\n` +
`Invalid JSON payload received. Unknown name "section": Cannot bind query parameter. Field 'section' could not be found in request message.`,
reason: 'invalid'
}
]
I believe your goal as follows.
You want to create new course using googleapis for Node.js.
Modification points:
At googleapis for Node.js, please put the request body to resource and/or requestBody.
I think that the reason of your error message is due to this.
When "id": "157942918368", is used, an error of Request contains an invalid argument. occurs.
When "courseState": "ACTIVE" is used, an error of "#CourseStateDenied This user cannot create or transition courses into the requested state." occurs.
"PROVISIONED" can be used in this case.
When above points are reflected to your script, it becomes as follows.
Modified script:
From:
const res = await classroom.courses.create(course);
To:
const res = await classroom.courses.create({ requestBody: course });
or
const res = await classroom.courses.create({ resource: course });
And also, please modify your request body as follows.
From:
{
"id": "157942918368",
"name": "English - 9Y",
"section": "Period 2",
"ownerId": "me",
"courseState": "ACTIVE"
}
To:
{
"name": "English - 9Y",
"section": "Period 2",
"ownerId": "me",
}
Note:
In this modification, it supposes that your const classroom = google.classroom({ version: 'v1', auth }); can be used for using the method of courses.create in Classroom API.
References:
Method: courses.create
googleapis for Node.js
What permissions do I need or what am I doing wrong with this SendGrid API call?
I'm trying to post a new recipient ( /contactdb/recipients ) to Send Grid but keep getting a 403 response:
I get this even when calling the API from the SendGrid Explorer
Contacts API - Recipients
POST -> Add recipients
{
"errors": [
{
"field": null,
"message": "access forbidden"
}
]
}
This makes me think that my API Key doesn't have enough permissions but it has Full Access.
Here is my client code as well.
require("dotenv").config();
const client = require("#sendgrid/client");
exports.handler = function(event, context, callback) {
const body = JSON.parse(event.body);
const email = body.email;
if (!process.env.SENDGRID_API_KEY) {
callback("No API Key");
}
client.setApiKey(process.env.SENDGRID_API_KEY);
const request = {
method: "POST",
url: "/v3/contactdb/recipients",
body: JSON.stringify([{ email }])
};
client
.request(request)
.then(([response, body]) => {
// console.log(response.statusCode);
// console.log(body);
callback(null, response, body);
})
.catch(error => {
// console.log(JSON.stringify(error.response.body.errors));
callback(error);
});
};
Per support:
We have just very recently released a "New Marketing Campaigns"
experience and the endpoints have changed from our "Legacy Marketing
Campaigns".
Try this endpoint:
https://api.sendgrid.com/v3/marketing/contacts
I pulled it from our documentation here:
https://sendgrid.api-docs.io/v3.0/contacts/add-or-update-a-contact
Update
Previous answer does not coordinating the issue directly, sendgrid recently changed their internal api's base url, creating list of recipients which internally are static collections of Marketing Campaigns contacts. This API allows you to interact with the list objects themselves. To add contacts to a list, you must use the Contacts API.
Legacy api :
/v3/contactsdb/lists
New functional variant
/v3/marketing/lists