A Script To Check Vaccination Slots

This is a story of how I put together a script for checking vaccination slots (in India). It’s pretty simple if you are a coder but this post is to explain the process to the general public.

Ok so here’s what I did as the first thing –

I visited the CoWin website, entered my pincode and clicked on the submit button. Then I right-clicked on the web page and clicked on “inspect element” (in Google Chrome).

Then I checked the “network” tab and tried submitting the form twice with different pincodes to see what requests are being sent each time I submit the form.

Here’s what I found –

You can see two requests at the bottom there, one for 400607 and the other for 400608.

If I click one either of those, I’ll see more information as follows –

I’m interested in the “Request URL”. If you copy this URL and paste it in the browser, you will get some structured response. Here’s an example –

It’s a little difficult to read it but we can prettify it by using an online JSON prettifier.

Here’s the pretty version of the same response –

{
"centers":[
{
"center_id":692991,
"name":"THANE Global Hub (18-44) 1",
"address":"Laxmi Nagar Balkum Pada Thane",
"state_name":"Maharashtra",
"district_name":"Thane",
"block_name":"Thane Municipal Corporation",
"pincode":400607,
"lat":19,
"long":72,
"from":"09:00:00",
"to":"13:00:00",
"fee_type":"Free",
"sessions":[
{
"session_id":"47494740-4324-4c0f-a092-24ab142414a2",
"date":"08-05-2021",
"available_capacity":0,
"min_age_limit":18,
"vaccine":"COVAXIN",
"slots":[
"09:00AM-10:00AM",
"10:00AM-11:00AM",
"11:00AM-12:00PM",
"12:00PM-01:00PM"
]
}
]
},
{
"center_id":695478,
"name":"THANE Global Hub (18-44) 2",
"address":"Laxmi Nagar Balkum Pada Thane",
"state_name":"Maharashtra",
"district_name":"Thane",
"block_name":"Thane Municipal Corporation",
"pincode":400607,
"lat":19,
"long":72,
"from":"14:00:00",
"to":"18:00:00",
"fee_type":"Free",
"sessions":[
{
"session_id":"1141f9c3-502c-4bce-8d45-38890b8db96e",
"date":"08-05-2021",
"available_capacity":0,
"min_age_limit":18,
"vaccine":"COVAXIN",
"slots":[
"02:00PM-03:00PM",
"03:00PM-04:00PM",
"04:00PM-05:00PM",
"05:00PM-06:00PM"
]
}
]
}
]
}

Since my end goal is to get an “alert” whenever there’s a slot available for my age (under 45), I’m only interested the following information –

min_age_limit
available_capacity

Logic

Alright, so here’s my logic –

“Send a request to that URL every X seconds and then process the response by checking whether any of the centers with min_age_limit of 18 has available_capacity that’s more than 0. If so, make an alert till I manually abort the script.”

Now this has to be converted into code in order to automate it. I used Python3 for this since it’s pretty simple and intuitive to use.

Let’s build the code step by step!

A Simple Request

Here’s a simple script that sends a request (to the specified URL) and prints the response –

import requestsurl = https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/calendarByPin?pincode=400607&date=08-05-2021r = requests.get( url )print(r.text)

Note: You can save it as test.py on your desktop and run it via terminal by switching to desktop cd desktop and typing in python3 test.py.

It produces the same response that we got before via the browser. Cool. I’m now interested in accessing the relevant parts of the response.

The Response

In order to access the contents of the response, I use the json package.

import jsonresponse = json.loads(r.text)print( response['centers'] )for center in response['centers']:
print( center['sessions'][0]['min_age_limit'] )
print( center['sessions'][0]['available_capacity'] )

This code along with the one above it allows me to send a request to a URL, get a response and access the contents of that response.

403 Response

After a while, I started seeing a 403 response when I made a request via Python3 but everything worked fine if I accessed it via the browser.

What happened there? Something changed on CoWin’s side. To fix it, I simply had to show that my request is actually coming from a browser.

This can be done by passing a user-agent header in our request as follows –

url = https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/calendarByPin?pincode=400607&date=08-05-2021headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36'} # This is chrome, you can set whatever browser you liker = requests.get( url, headers=headers )

Params

Similarly, we can take the pincode and date parameters out from the url and pass them as params in our request as follows –

url = https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/calendarByPinheaders = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36'} # This is chrome, you can set whatever browser you likepayload = { 
'pincode': 400607,
'date': '08-05-2021'
}
r = requests.get( url, headers=headers, params=payload )

Make Some Noise

I wanted the script to make some noise and alert me whenever a slot was available so I could go and book it asap.

Here’s a neat little trick that helps to create a beep noise. This will beep three times –

import osbeep = lambda x: os.system("echo -n '\a';sleep 0.2;" * x)beep(3)

There’s also a way to make the computer say whatever you want it to say. For example –

import osos.system( "say VACCINE ALERT VACCINE ALERT")

It’s silly but gets the job done.

Repeat The Code Every X Seconds

Now I have everything to put together something decent but I still need a way to repeat my code to automatically check for a slot, right?

To do this, I use the sleep method from the time package –

import timestarttime = time.time()
seconds = 30.0
while True:
print( 'Hello' )
time.sleep ( seconds - ((time.time() - starttime) % seconds) )

This simply prints “Hello” every 30 seconds. I’m sure there’s a better way of doing this but I just did a quick Google search and got this snippet from StackOverflow.

Processing The Response

Now it is time to finally process the response using some “logic” that we discussed above.

I defined a function that processes the response based on the payload (the date and the pincode) that we send to it –

Note: I’m sharing it as a screenshot because it is too difficult to read in medium’s code block.

  • The code above is making a request using params and headers and stores the response in r.
  • If r is all okay and didn’t return any errors, it loads the content of r as json inside the response variable. If it did return any errors, it simply exits the function.
  • Next it checks whether the response contains a list of centers.
  • If it does, check each center in the list of centers as follows –
  • If the center has min_age_limit as 18 and available_capacity is greater than 0 then make some noise and print that a “slot is available” (with date and pincode). Otherwise print “no slots”.
  • If there’s no center in the list of centers then print “no centers”.

Putting Everything Together

Putting everything together, here’s what I got in the end –

Just for testing purposes, it checks for an update every 2 seconds for the given date and two payloads (two pincodes).

Once a slot is available, it will keep beeping with the alert message till you manually abort the program.

Here’s a link to the final code in case you’re interested.

It’s not great. It’s just okay and gets the job done. Plus, it’s good stuff for explaining “APIs” to the general public ;)

Talking of APIs, CoWin’s public APIs are available here.

Thanks for reading! :)

Edit –

If you run into the “requests module missing” error, you can install it by opening the terminal and typing in python3 -m pip install requests command. You can use the same command to install other missing modules (if any).

I explain stuff!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store