CoWIN - Exploring the API
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
Overview
CoWIN has made its APIs publicly available. Details about version 2 are documented on the API Setu website.
Most online discussions focused on notification services using the API to alert users of new slots. Services like getjab and VaccinateMe emerged alongside Telegram groups and PayTM’s Vaccine Slot Finder tool.
However, these tools lacked actual booking automation. Given rapid slot availability depletion, I pursued automating the complete booking process upon slot detection.
API Structure
The CoWIN system divides into Public APIs and Protected APIs.
Appointment Availability APIs power notification features with both public and private endpoints:
- Public endpoint requires no authentication but returns cached data (up to 30 minutes old)
- Private endpoint requires authentication
The booking endpoint /v2/appointment/schedule demands authentication via POST request.
Booking Request Structure
data = { "center_id": center_id, "session_id": session_id, "beneficiaries": [beneficiary], "slot": slot, "dose": 1}Parameters:
- center_id, session_id, slot: sourced from Appointment Availability API responses
- dose: either 1 or 2 depending on vaccination round
- beneficiary: extracted from decoded JWT Access Token
Authentication & Headers
Repeated 403 Forbidden responses prompted header spoofing to simulate browser requests:
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',}Obtaining JWT Access Token
- Log into the CoWIN self-registration portal via desktop
- Access browser Session Storage
- Locate the userToken variable containing your JWT Access Token
- Decode at jwt.io
Decoded token contains:
{ "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"}Use beneficiary_reference_id in booking requests and the full encoded token in authentication headers.
Implementation
A proof-of-concept Python script automating slot discovery through booking is available in a GitHub Gist. The code requires cleanup but functions as a demonstration.
Observations & Speculations
- Frequent API hits result in IP-level bans; authenticated requests may also receive 403 responses, possibly indicating location-based restrictions
- User tokens expire after approximately 30 minutes, requiring re-authentication via OTP
- Despite API documentation claiming 100 requests per 5 minutes, practical thresholds appear significantly lower (approximately 10 requests/minute)
- GET Appointment Availability APIs work with or without authentication, possibly unintended
- POST methods require authentication, returning 401 Unauthorized without valid tokens
- User-Agent header spoofing appears essential to prevent 403 responses