GreenAPI + Gemini + Cloud Run + FastAPI will take you a long way

I recently joined a tennis club in Brazil that runs a year-round ranking tournament through WhatsApp. With around 90 players, match coordination and ranking updates create a lot of manual work for both players and the admin, so I started exploring how AI could reduce that friction.
Before automation, most operational work was manual by messages in WhatsApp:
- Scheduling and availability Players had to coordinate opponent, court, date, and time through chat, while also checking ranking-range rules and existing scheduled matches.
- Ranking visibility Ranking and schedule updates depended on when the admin could post them, so players often waited to know who they could challenge.
- Score processing Scores were submitted in group messages and then interpreted and processed manually.
- Name ambiguity Players were often referred to by nicknames or first names, making identity matching harder, especially for newer members.
Design constraints were straightforward: keep WhatsApp as the interface people already use, preserve the group’s casual community style, support non-technical users, minimize maintenance and cost, avoid disrupting court scheduling, and keep ranking updates fast and reliable.
Ranking Tournament Logic
The tournament uses a pyramid ranking model, which simplifies result computation. Rankings are arranged as follows:
Ranking Pyramid
1
2·3
4·5·6
7·8·9·10
11·12·13·14·15
16·17·18·19·20·21
22·23·24·25·26·27·28
29·30·31·32·33·34·35·36
In a nutshell, the rules are:
- A player can only challenge another player in their own pyramid level or the one above.
- Player status alternates between Awaiting Challenge and Challenger after each match.
- It is the responsibility of the Challenger to arrange a match with someone marked Awaiting Challenge, and the Awaiting Challenge player must accept.
- If the Challenger wins, rankings are swapped. If the Challenger loses, rankings stay the same but the statuses alternate.
It reminds me of bubble sort.
Optimistic Solution vs Realistic Solution
I first thought of automating everything, but after talking with the admin and observing the group, it was clear scheduling had too many human exceptions and too much operational risk.
So I narrowed the scope: help players arrange matches faster and reduce ranking workload, without touching lessons or court rentals.
I also rejected a web app because extra authentication would hurt adoption in a WhatsApp-native workflow.
One rule stayed fixed: the admin has final override, and admin updates are always the source of truth.
Why Not WhatsApp Business
I also explored WhatsApp Business as an option. It is powerful, but for this use case it came with tradeoffs that did not fit the club’s current dynamic.
- It usually requires more admin/business setup than we wanted at this stage.
- The bot cannot just behave like a regular group member in the same way a normal person can.
- It tends to push interactions toward structured flows, while our group works best with free-form messages.
I wanted to preserve was the natural style of the community: jokes, informal language, and flexible conversation. I did not want the experience to feel like filling out a form.
Compromises
The compromise was simple: automate high-friction tasks without changing how the group already works.
- Keep scheduling with the admin.
- Keep interactions in WhatsApp.
- Process only operational group messages (scores, ranking updates, scheduled matches).
- In private chat, help players find legal opponents and share direct WhatsApp contact links.
- Reduce manual admin work while giving players faster, clearer updates.
Solution

The architecture keeps WhatsApp as the primary interface and adds a lightweight automation layer around ranking operations.
WhatsApp Group + Private Chat: Keeps behavior unchanged, group for operational posts, private chat for personalized guidance.
Green API: Bridges WhatsApp messages to the backend via webhooks. For each message, forwards content, raw metadata, and auth headers. It made backend integration straightforward, since FastAPI could process incoming webhook payloads and respond with simple HTTP calls.
Runtime/Hosting Layer: Runs the same FastAPI service in development and production. ngrok exposes local webhooks; Cloud Run hosts public production endpoints.
FastAPI Service: Routes events and applies tournament rules. Endpoints: /webhook, /send-ranking, /send-news, /send-weekly-summary.
Message classification and access checks: is_group and is_admin are computed in FastAPI from webhook metadata. Controls which workflows are allowed in group and private chats.
Group workflows: Admin can override ranking and scheduled matches (update_ranking, update_matches). Players can submit results and request ranking (submit_score, get_ranking).
Private assistant workflows: Helps players schedule legal matches faster. Uses actions such as get_players_that_i_can_challenge`, get_players_that_can_challenge_me, get_matches, get_ranking, and get_player.
Gemini Intent Module: Converts free-form messages into structured intents while keeping backend actions deterministic.
Gemini News Module: Generates tennis headlines and a weekly summary from recent scores and ranking.
Cloud Scheduler: Triggers periodic jobs like /send-news, /send-weekly-summary, and /send-ranking.
Cloud Storage: Persists tournament state. Players: identity and metadata. Matches: scheduled/reported records. Ranking: standings source of truth. I intentionally avoided a traditional database in this phase to keep the architecture simple and low-maintenance.
End-to-end design intent: Automate ranking management and player discovery without replacing human scheduling. Admin keeps control; players get faster, consistent information in WhatsApp.
Examples


Main Challenges
Players’ names: Matching internal logic to free-form names was the hardest part. I used a mix of prompt context (official names) plus custom logic that combines fuzzy matching and tournament rules to infer the intended player.
Rules Enforcement: Even with clear rules, the community is flexible and exceptions happen naturally when the admin understands the context. AI is less flexible by default, so some cases were difficult at first. For example, young players sometimes have a parent post the score, but by rule only involved players can submit results.
Costs
From day one, the goal was to keep costs low. To prove value first, I currently cover GCP and Green API costs myself while we validate long-term usefulness and real operating expenses.
Current monthly cost:
- Green API: about $12/month
- GCP: about $0/month for now, since the main Cloud Run usage is still within the free tier
- Gemini: about $6/month
So at the moment, total operating cost is roughly $18/month.
Conclusion
Today, the bot is already helping the players: it processes match updates, keeps rankings current with less admin effort, and supports players in private chat when arranging matches.
For me, the project has been rewarding and educational. Even if long-term adoption is still uncertain, it proved that practical, low-cost AI can support real community workflows.
This post focuses on the core idea, so many implementation details, edge cases, and constraints are intentionally left out.
How I Introduced AI in My Tennis Club was originally published in Towards AI on Medium, where people are continuing the conversation by highlighting and responding to this story.