◉GEMINI LABJP
●CLI 0.63.0 — Gemini CLI 0.63.0 (Oct 6) shows retry progress on reconnect, tells a missing MCP config from broken JSON, and caps tool output in long agent loops●10/29 — 22 days until the image model gemini-3.1-flash-image shuts down. Move to gemini-nano-banana-2.1, added on Oct 6●10/22 — 15 days until the three Veo 3.1 models shut down. The place to move is gemini-omni-1.1-flash●NOTICE — A Zenn post reports that a plugin's admin screen said nothing when an AI model was retired. How to avoid missing such notices is the real question●NEW — Three Veo 3.1 previews stop on 10/22. Before swapping them, here is how to inventory every place that calls them●CLAUDE — Zenn keeps getting posts on handing Codex or Claude Code writing to Gemini. The real question is which jobs to hand over and which to keep●CLI 0.63.0 — Gemini CLI 0.63.0 (Oct 6) shows retry progress on reconnect, tells a missing MCP config from broken JSON, and caps tool output in long agent loops●10/29 — 22 days until the image model gemini-3.1-flash-image shuts down. Move to gemini-nano-banana-2.1, added on Oct 6●10/22 — 15 days until the three Veo 3.1 models shut down. The place to move is gemini-omni-1.1-flash●NOTICE — A Zenn post reports that a plugin's admin screen said nothing when an AI model was retired. How to avoid missing such notices is the real question●NEW — Three Veo 3.1 previews stop on 10/22. Before swapping them, here is how to inventory every place that calls them●CLAUDE — Zenn keeps getting posts on handing Codex or Claude Code writing to Gemini. The real question is which jobs to hand over and which to keep
Articles/API / SDK
◈ API / SDK/2026-07-03Advanced

A Webhook Is a Claim, Not a Fact — Three Layers of Defense for Your Gemini Webhooks Endpoint

Your Gemini Webhooks receiver is a public URL, which means forged events, replays, and duplicate deliveries are all on the table. This walkthrough builds a three-layer defense — reachability checks, dedupe, and a lightweight handler that re-fetches truth from the API — with working FastAPI and SQLite code.

Gemini API245Webhookssecurity12idempotency5automation54

✦ Premium Article

After I moved my Gemini Batch monitoring from polling to Webhooks, I reread the receiving code and stopped cold. Somewhere along the way I had assumed that only Google would ever POST to that URL. In reality, a webhook receiver is a public internet endpoint. Anyone who finds it can send it any JSON they like.

Webhook receivers in indie projects tend to start life as "whatever works." I would have shipped mine wide open too, if I hadn't spent years operating Stripe webhooks for the membership billing behind my Dolice Labs sites. In the payments world, "trusting the webhook too much" is a textbook failure mode, and the discipline that grew around it transfers directly to Gemini automation pipelines. Here is the three-layer defense I ended up with, along with code that runs.

What actually goes wrong with an unguarded receiver

Before designing defenses, it helps to name the failure modes. If your receiver believes whatever JSON arrives, three things can happen.

Forged events. An attacker — or simply a misconfigured system somewhere else — POSTs a payload dressed up as a "job completed" notification. If the receiver takes it at face value and kicks off downstream work, you end up fetching results that don't exist, saving empty artifacts, or pushing unfinished data into a publish step. No malice is required: staging notifications landing on a production endpoint is a real, mundane accident.

Replays. A legitimate event you already handled arrives again. Deliberate replay is one cause, but ordinary delivery retries produce the same effect. The downstream side runs twice, burning compute or overwriting data you already published.

Duplicate processing. If your handler responds slowly, the delivery side times out and resends. The heavier the synchronous work inside your handler, the slower it responds, the more retries pile up — a self-reinforcing loop.

Note that the last two happen without any attacker at all. Defending against malice and defending against retries land in almost the same code. I covered event ordering separately in A Finished Gemini Job Flipped Back to 'Running' — Stopping Out-of-Order Webhooks with Monotonic State Apply; this piece focuses on the receiving endpoint itself.

The principle — a payload is a notification, not a fact

One rule underpins all three layers: never update state from the webhook payload.

Treat every incoming event as a hint that "something may have changed," and always re-fetch the actual state from the Gemini API. Even if the payload says state: succeeded, that is not a reason to run downstream work. You run it only when your own query confirms completion. This single move structurally defuses forged events: the only thing an attacker can fabricate is a reason to check, while the facts live solely on the API side.

This is a direct continuation of the reconciliation design I wrote up in When a Deploy Drops the Webhook: Reconciling Gemini Long-Running Operations with a Belt-and-Suspenders Design. If you already reconcile against the API to catch dropped events, the very same query logic doubles as your "don't trust the payload" mechanism. You barely need any new parts.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦You'll be able to harden a wide-open webhook receiver against forged events, replays, and duplicate processing with three inexpensive layers
✦You can implement the 'notification vs. fact' separation — never trusting the payload, always re-fetching state from the API — with working FastAPI and SQLite code
✦You'll take away a cost-vs-benefit table for each defense, adapted from payment-webhook discipline to Gemini automation pipelines
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $15 for lifetime access
View Membership →

Related Articles

◈ API / SDK2026-09-29
The Size Column Said 'F6' and 'About A4' — I Let Gemini Read It, and Let a Table Do the Math
An artist's spreadsheet mixed 'F6', '41×31.8cm', and 'about A4' in one size column. Here is the small tool I built: Gemini reads each cell, a lookup table converts to centimeters, and the artwork image decides the orientation. Working code, step by step.
◈ API / SDK2026-09-22
When Function Calls Turn Into Plain Text, Suspect the Property Names in Your Tool Declarations
A record of chasing MALFORMED_FUNCTION_CALL after output limits and schema conflicts were ruled out, bisecting nine tool declarations down to one property name, and adding a linter that stops bad names before they ship.
◈ API / SDK2026-09-12
gemini-2.5-flash-image stops on October 2, and the replacement the table names retired in June
gemini-2.5-flash-image shuts down on October 2, 2026, but the recommended replacement listed in the official table, gemini-3.1-flash-image-preview, was already retired on June 25. Here is the script I wrote to follow replacement chains to their end, and what it found across every row of the table.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links