I don’t get many chances to play tennis.
Between work, everyday constraints, and lately some pretty uncooperative weather, court time is rare and valuable. So when I finally found a slot that worked — and the booking system refused to give it back — frustration set in fast.
A Slot That Existed… but Didn’t
After canceling a reservation by mistake, I tried to book the same court again.
The global search page clearly showed one available slot for that day.
But when I clicked through to the court page, instead of seeing the list of available time slots and a “Reserve” button, I got this message:
Sorry, there is no court available for the selected date and criteria.
So the platform was telling me two contradictory things:
- Search results said the slot existed
- The court page claimed there were no slots at all for that day
When you already don’t have much time to play, that kind of bug is incredibly frustrating.
When You Stop Trusting the UI
Refreshing didn’t help. Navigating back and forth didn’t help. The slot stayed visible in search, but the court page refused to display it.
At that point, I stopped trusting the interface.
If the system was able to count the availability, then the data had to exist somewhere — even if the UI failed to render it.
Watching the Site Talk to Itself
I opened Chrome DevTools and switched to the Network tab.
I replayed the booking flow and watched the HTTP requests being made.
One thing stood out:
- The same court
- At the same time
- Worked perfectly on the previous day
Clicking “Reserve” for that earlier date led straight to the reservation confirmation page.
So I captured that request.
Right-click → Copy as fetch → paste into the console.
The Request (Sanitized but Structurally Identical)
Below is the request as captured, with:
- A fake domain
- A clearly fake anti-bot token
- Everything else left untouched to preserve realism
fetch("https://tennisresa.fake/tennis/Portal.jsp?page=reservation&view=reservation_captcha", {
"headers": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7",
"cache-control": "max-age=0",
"content-type": "application/x-www-form-urlencoded",
"priority": "u=0, i",
"sec-ch-ua": "\"Chromium\";v=\"134\", \"Not:A-Brand\";v=\"24\", \"Google Chrome\";v=\"134\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "same-origin",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1"
},
"referrer": "https://tennisresa.fake/tennis/Portal.jsp?page=recherche&view=rechercher_creneau",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "equipmentId=320&courtId=3012&startDate=2026%2F01%2F14+12%3A00%3A00&endDate=2026%2F01%2F14+13%3A00%3A00&cancelling=false&li-antibot-token=FAKE.JWT.TOKEN_FOR_BLOG_POST_ONLY&li-antibot-token-code=100&captchaRequestId=FAKE-CAPTCHA-ID-123456",
"method": "POST",
"mode": "cors",
"credentials": "include"
});
What I Changed (Almost Nothing)
This is the key point.
I did not attempt to:
- Forge a new request
- Bypass authentication
- Remove the anti-bot mechanism
I deliberately kept the request exactly as generated by the site, because it already contained important context:
- Session cookies
- Headers
- Anti-bot token
- Navigation intent
I changed only two parameters:
startDateendDate
That’s it.
It’s essentially the same as refreshing a POST-based page, but with slightly modified input — like correcting a date in a form the UI refused to let me submit.
The Result
After canceling any pending attempt, I executed the modified request in the console.
I refreshed the page.
And suddenly, I was on the reservation confirmation page — for the exact slot that the UI had claimed didn’t exist.
The backend accepted it.
The booking went through.
That Feeling of Power
I didn’t exploit a vulnerability. I didn’t defeat the anti-bot system. I didn’t “hack” anything in the dramatic sense.
But in that moment, I felt powerful.
With:
- A browser
- Chrome DevTools
- And minimal technical knowledge
…I worked around a system bug that blocked a rare, real-life moment.
What This Really Shows
This wasn’t about hacking.
It was about:
- UI and backend desynchronization
- Cached or inconsistent availability state
- A backend that trusted valid requests more than its own interface
The UI said “no”. The backend said “yes”.
I simply spoke the backend’s language.
Final Thoughts
Websites are just software. Software has bugs. And sometimes, those bugs stand between us and the things we enjoy.
Knowing how to open DevTools doesn’t make you dangerous — it makes you less powerless.
That day, I didn’t just book a tennis court.
I took back control. 🎾