A few days ago, I went to a cafe near my home. I sat down and scanned the QR code on the table. It took me to a website displaying the cafe's menu. It asked me for my name and Whatsapp mobile number. I entered the details and placed the order.
In 5 mins my order arrived at the table. There was no OTP verification, and no one came to confirm the order. Is this what the peak ordering experience looks like?
It was a slow workday, and I thought I might as well open this QR code website on my laptop and have a quick look under the hood. Maybe I should've just made my own coffee and stayed home because I didn't realize I was opening a can of worms.
The QR code directed me to a website that ran on a dotpe.in subdomain. According to Dotpe’s website, they offer a "full stack food stack" for restaurants. The company was founded during the pandemic when contactless dining became popular. Google is one of their investors.
I opened my browser's dev tools to inspect the API requests - they looked OK. A request to get details of the cafe, a request to get all the items on the menu, a request to check if the store is running any promotional offers - just the usual stuff. Then I saw a couple of interesting requests:
/api/morder/suggestion/ongoing/items?storeID=XXXX
/api/morder/suggestion/items/purchase/history?merchantID=YYYY&storeID=XXXX
The first request listed the food items currently ordered at the cafe. The second returned how many times each item was ordered in the past month.
The coffee I had ordered showed up on the list of ongoing items. I looked around the cafe and noticed other food on tables matched items on the list too. This information should be for the cafe's admin staff only, so why can I see it?
The purchase history API provided a count of each food item ordered over the past month. The menu API gave the price of each food item. So I wrote a small script to calculate the cafe's dine-in revenue for the last month.
Should I really be privy to this information?
Are there other unauthenticated APIs leaking important information? There are so many. For example:
/api/morder/suggestion/items/past-fav?storeID=XXXX&merchantID=YYYY&phone=9999999999
This returned my previous orders at this cafe. They probably use this data to show my past orders in the menu for reordering. Similar to what Swiggy or Zomato do. It is an understandable use case. But I changed the mobile number to my friend's, who had been to the cafe before, and I could see their past food orders too. That's not good!
Here is another example:
/api/morder/fd/table/state?storeID=XXXX&tableID=TT
This one returned my name, mobile number, a numeric order ID, and an order hash ID of the order I had placed on my table. Standard stuff.
But then I changed the table ID which was just a number (01) to the table ID (02) of the guy sitting across from me. I could see his name, mobile number, and order details. From the order ID hash, I could now also see what items he had ordered and what his bill was. From the mobile number, I could see all the food he had ever ordered in this cafe. I felt dirty that I knew that this stranger across the table had ordered Oat Milk Iced Vanilla Latte 18 times in this cafe.
This is just one cafe. Dotpe has thousands of dine-in restaurants across India. Can I see what everyone in India is currently eating in real-time at all these restaurants? Also, can I find out each restaurant's sales from last month? I'm perplexed as to why Dotpe is allowing me to see this. Surely their merchants won't apperciate a random online person lurking around accessing their monthly sales figures.
I searched for Dotpe subdomains indexed by Google. It returned thousands of search results. I still loved my life so I didn't want to use the Google custom search API. Luckily, Dotpe themselves have a simple API to do this:
/api/merchant/external/store/XXXX?serviceSubtype=fine
Store ID is a number. I just had to loop through them beginning from 1. Armed with my two-week free trial of Cursor IDE, I quickly fetched details of all of Dotpe's dine-in merchants. There was no rate limiting either. Thanks Dotpe, your endpoints design and API restrictions are a web lurker's dream 🤌
I could now see all the ongoing orders from all their restaurants in real time! I was so tempted to build a website that shows all the live food orders on a map. Like this guy who created a site tracking all the broken ice cream machines at McDonald's across the US. But Dotpe can at any time flick a switch to restrict access or shut down this API. So I didn't think it was worth the effort.
37,529 restaurants use Dotpe for QR codes. This includes big chains like Starbucks, Pizza Hut, Haldiram's, Social, Barista, and Paradise Biryani. Of these, 2,052 are either closed, defunct, or used as internal test or dummy restaurants. From my analysis, they currently have 10,866 operational dine-in restaurants.
Now that COVID restrictions are no longer in place, it appears that restaurant chains such as Starbucks, Pizza Hut, and Barista have abandoned Dotpe's QR code services. Last month's purchase history data for these brands showed only a very few items. In fact, only 1,314 restaurants had a food item ordered in the last month.
On the other hand, a few restaurant chains have embraced Dotpe's platform in a huge way. Two notable examples are The Social and Paradise Biryani.
The Social's data is especially interesting. Their order numbers are mind-boggling. Most of their pubs across the country are doing incredible business. There are 53 operational Social pubs in the country.
I wrote a little script to calculate their earnings from all their pubs. And here is the data:
Of course, it depends on the accuracy of Dotpe's data, but they're making some 18.3 crores from their dine-in business. Which would make it more than 200 crores a year. That's a lot of money! I still can’t believe I’m allowed to see this!
I noticed a fun difference between top-selling items in various Socials. Typically, Nachos are the bestseller in most Socials, but in most North Indian Social branches, "Banarasi Patiala with Vodka" is almost always the top-selling item. Make of this what you will.
Here is a list of top-selling item at each Social:
Regarding Paradise Biryani restaurants - the Secunderabad, Hyderabad branch stands out as an outlier with a monthly business of INR 72.89 Lakhs, far surpassing the sales of other branches. I'm not convinced that Dotpe QR codes are widely used by all Paradise Biryani restaurants but I could be wrong. This is still decent numbers.
There are so many fun little insights from Dotpe’s historical purchases data about so many other restaurants. Maybe I should do a separate post about it.
From studying how Dotpe's ordering API calls work, I figured out that I can remotely place an order at any restaurant table where people were already sitting without needing their table PIN. For obvious reasons, I will spare the details - but it was very straight-forward.
I was interested to see if this would work in real life and what would happen when this ghost order made by me showed up on the victim's table. To test this, I went to one of Social's pubs near me. I sat at table T-26. I checked on my laptop what other tables were ordering to get a quick vibe check of the place. I could've just looked around, but it felt cooler to do it on the laptop.
The music was too loud as usual. I scanned the place to find a suitable target to execute my diabolical plan. I spotted a table in my line of sight where two not-too-intimidating-looking guys were sitting and drinking beer. Their table ID was easy to find. It was written in a big font on their table.
I opened up their table's QR code webpage on my laptop. I scanned the API calls to get all the details I needed. I did my thing and I was in. I added a Crispy Corn Soup to the cart. It was the first thing on the menu. I swiped the Place Order button and the order was placed.
I shut down my laptop and waited. My heart was racing. I could feel a pit in my stomach thinking about the awkward situation that was about to happen. The soup arrived. I almost didn't want to watch this unfold. When the waiter put the soup on the table, both the guys at the table looked confused. One of them said they didn't order it. The waiter took out his tablet and showed them the order was placed by their table. The guys at the table repeated that they didn't order it. It was becoming painful to watch. Luckily, and to my relief, after a brief discussion with another staff member, they took the order back and everything was resolved amicably. It was an excruciating experience.
But it worked. This means I could write a script to remotely place orders at every restaurant table in the country that used Dotpe's QR codes. But this would raise alarm bells instantly. I clearly don’t have the stomach for it, but do you know what a really evil person would do? They’d write a script that periodically places small orders at random tables at random restaurants at random times. This would create a touch of disorder to cause a mild inconvenience but not enough to raise suspicions of anything nefarious. They could keep this script running for months, even years, creating awkward scenes and uncomfortable conversations at every restaurant across the country.
I need to speak about one more API endpoint:
/api/morder/fd/table/state?storeID=XXXX&tableID=TT&OrderID=OOOO
I found that for any live order on a table, if I changed the order ID (again a numeric ID 🤷♂️), I could get details of any order made anywhere in India, including all historical records. I could retrieve orders going as far back as 2021.
This means I could run a simple loop and access all food orders ever made via Dotpe. If you ever went to a restaurant and scanned a QR code that opened Dotpe's website, I can see what you ordered and how you paid.
I could then extract these orders by mobile numbers. I could use easily available leaked personal data about you to collate and consolidate more information about you. I can think of one or two companies that would be interested in this data. I'd be surprised if Dotpe isn't already selling this data to third parties.
I would have thought about privately disclosing these findings to Dotpe. But all the API requests are right there in plain sight for anyone at Dotpe taking even a cursory look at their own websites. I refuse to believe they’re unaware of this. This doesn’t feel like an oversight, it's either a deliberate design decision or they just don't care.
Their APIs lack so many very basic good practices. They could do so much to deter casual lurkers like me while also keeping their endpoints open and unauthenticated. But hey look, I am not complaining. In a world where everyone is putting up hard walls around their online spaces, it is refreshing to see a no fucks given platform give unbridled access to randos like me. Love you Dotpe.
Next time you're at a restaurant that makes you scan a QR code and enter your mobile number to order, I want you to remember that random strangers on the internet are looking over your shoulder and watching what you're eating.
Great work. Wonder if the Income Tax people keep an eye on the sales figures.
Very interesting findings that point to extremely poor data protection effort by the service provider. I think there is a consumer case for damages against the restaurants using the service - waiting to happen.