Just to be fair this has not been tested. This is not the way I booked my slot for the vaccination.
TL;DR: You can probably automate vaccination slot booking
It is common knowledge that CoWIN has opened up its APIs. You can find more details about version 2 of their APIs on the API Setu website (I'm yet to meet someone who gets their APIs right in v1 😛).
Most of the writeups which I found online were of people using the API for notifying them of new slots opening up. Some have already created notification services around it like getjab and VaccinateMe along with a few Telegram groups popping up to serve the same purpose. Even PayTM has launched a Vaccine Slot Finder tool.
But all these tools were missing a critical component, which was to actually book the slot. Due to shortage of vaccine availability these slots get filled up before anyone has time to react to the notifications. I wanted to go 1 step further and automate the booking process on availability of the slot.
The APIs are divided into 2 parts Public APIs and Protected APIs. The most important are the Appointment Availability APIs which are essentially what are used for the notifications feature. They have both a public and a private endpoint. The public endpoint does not need any form of auth, however it may return relatively older data (upto 30 mins old) due to returning from cache. The private endpoint requires auth (although I've hit it numerous times without auth, and it has returned the available slots successfully).
But for booking a slot using /v2/appointment/schedule I believe auth is critical.
A POST request needs to be made to the above mentioned endpoint, with the following data
data = {
"center_id": center_id,
"session_id": session_id,
"beneficiaries": [beneficiary],
"slot": slot,
"dose": 1
}
The center_id, session_id and slot parameters are obtained from the response of the Appointment Availability APIs. The dose parameter is either 1 or 2 based on which vaccination shot you're going in for. And the beneficiary is obtained from decoding your JWT Access Token.
While testing this out I faced numerous 403 Forbidden responses, reasons for which I've mentioned at the end of the post. A 403 potentially indicates a ban, and given I didn't have enough data to infer the cause of the ban, I chose to spoof the headers on my request, so as to make it appear to be coming from a browser. You can find the headers used in my request below.
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'en-US,en;q=0.5',
'Origin': 'https://selfregistration.cowin.gov.in',
'Authorization': f'Bearer {access_token}',
'DNT': '1',
'Connection': 'keep-alive',
'Referer': 'https://selfregistration.cowin.gov.in/',
'Sec-GPC': '1',
'TE': 'Trailers',
}
The access_token mentioned above is used for the authentication of your request. You may read more about the same at jwt.io. They also have an in browser JWT Token decoder on their homepage. To get your personal JWT access token you'll have to login to the self registration cowin portal (use a PC). Once logged in, check the Session Storage of your Browser (told you to use a PC) and your JWT Access Token will pe present in the userToken variable. You may use decode this on jwt.io to fetch more details.
{
"user_name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"user_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"user_type": "BENEFICIARY",
"mobile_number": xxxxxxxxxx,
"beneficiary_reference_id": xxxxxxxxxxxxxx,
"ua": "Mozilla/5.0 (X11; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0",
"date_modified": "2021-05-05T14:32:15.194Z",
"iat": xxxxxxxxxx,
"exp": xxxxxxxxxx
}
For obvious reasons I've censored out the sensitive information. You may use this decoded JSON to get your beneficiary ID since it is a required data argument in the POST request. And the entire encoded userToken can be used as is, in the headers for auth.
I've a added a simple python script to automate the entire process from finding a slot to booking a appointment in a GitHub Gist. The code certainly could use a lot of cleanup. It is just intended to be a proof of concept. Feel free to use / modify it as required.