{"id":849,"date":"2026-05-05T15:01:53","date_gmt":"2026-05-05T07:01:53","guid":{"rendered":"https:\/\/connectword.dpdns.org\/?p=849"},"modified":"2026-05-05T15:01:53","modified_gmt":"2026-05-05T07:01:53","slug":"google-adds-event-driven-webhooks-to-the-gemini-api-eliminating-the-need-for-polling-in-long-running-ai-jobs","status":"publish","type":"post","link":"https:\/\/connectword.dpdns.org\/?p=849","title":{"rendered":"Google Adds Event-Driven Webhooks to the Gemini API, Eliminating the Need for Polling in Long-Running AI Jobs"},"content":{"rendered":"<p>If you\u2019ve ever built a production AI pipeline that runs long jobs \u2014 processing thousands of prompts overnight, kicking off a Deep Research agent, or generating a long video \u2014 you\u2019ve almost certainly dealt with the polling problem. Your code sits in a loop, firing <code>GET<\/code> requests every few seconds asking, \u201cIs the job done yet?\u201d It\u2019s wasteful, it adds latency, and at scale it becomes a reliability headache. Google just shipped the fix.<\/p>\n<p>Google introduced <strong>event-driven Webhooks<\/strong> for the Gemini API \u2014 a push-based notification system that eliminates the need for inefficient polling. The feature is available now for all developers using the Gemini API and targets a core pain point in agentic and high-volume AI workflows.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Why Polling Breaks Down at Scale<\/strong><\/h3>\n<p>To understand the problem, it helps to know what Long-Running Operation (LRO) is. Webhooks allow the Gemini API to push real-time notifications to your server when asynchronous or Long-Running Operations complete, replacing the need to poll the API for status updates and reducing latency and overhead.<\/p>\n<p>Before webhooks, the only option was continuous polling \u2014 repeatedly calling <code>GET \/operations<\/code> to check if a job had finished. As Gemini shifts toward agentic workflows and high-volume processing \u2014 like Deep Research, long video generation, or processing thousands of prompts via the Batch API \u2014 operations can take minutes or even hours. Polling for hours is expensive in both compute and API quota, and it introduces unnecessary delays between when a job completes and when your application learns about it.<\/p>\n<p>The fix is conceptually simple: instead of your code asking \u201care you done?\u201d repeatedly, the Gemini API calls your server the moment a task finishes, by pushing a real-time HTTP POST payload to your endpoint the instant a task completes.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Two Configuration Modes: Static and Dynamic<\/strong><\/h3>\n<p>The Gemini API supports two ways to configure webhooks. Static webhooks are project-level endpoints configured with the WebhookService API and are suited for global integrations like notifying Slack or syncing a database \u2014 they are registered once per project and trigger for any matching event. Dynamic webhooks are request-level overrides that pass a webhook URL in the <code>webhook_config<\/code> payload of a specific job call, making them ideal for routing specific jobs to dedicated endpoints, for example in agent-orchestration queues.<\/p>\n<p>You can think of static webhooks like a standing instruction to your mail carrier: \u201cAlways deliver packages to the front desk.\u201d Dynamic webhooks are more like saying: \u201cFor this one shipment, send it to my home address.\u201d An additional feature of dynamic webhooks is the <code>user_metadata<\/code> field, which lets you attach arbitrary key-value metadata to a job at dispatch time \u2014 for example, <code>{\"job_group\": \"nightly-eval\", \"priority\": \"high\"}<\/code>. This metadata travels with the job notification and is particularly useful when you need to fan out different job types to different downstream processors without building a separate tracking layer.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Security Architecture: Standard Webhooks, HMAC, and JWKS<\/strong><\/h3>\n<p>Security is where this implementation gets technically interesting. Google\u2019s implementation strictly adheres to the Standard Webhooks specification. Every request is signed using <code>webhook-signature<\/code>, <code>webhook-id<\/code>, and <code>webhook-timestamp<\/code> headers, ensuring idempotency and preventing replay attacks.<\/p>\n<p>For static webhooks, the signing is done with HMAC (Hash-based Message Authentication Code) using a symmetric shared secret, which is provided once at creation time and must be stored securely in your environment variables \u2014 the API returns this signing secret only once and it cannot be retrieved again. If you lose it, you have to rotate it. The rotation endpoint supports a <code>revocation_behavior<\/code> parameter \u2014 specifically <code>REVOKE_PREVIOUS_SECRETS_AFTER_H24<\/code>, which keeps the old secret valid for a 24-hour grace period so you can safely transition production systems, or an immediate revocation option for incident response.<\/p>\n<p>For dynamic webhooks, Google uses asymmetric public-key JWKS (JSON Web Key Set) signatures instead of symmetric secrets. Dynamic webhook requests emit a JSON Web Token (JWT) signature, and your listener must extract and verify it using Google\u2019s public certificate endpoints at <code>https:\/\/generativelanguage.googleapis.com\/.well-known\/jwks.json<\/code>. The RS256 algorithm is used for this verification.<\/p>\n<p>This means your server never blindly trusts incoming requests \u2014 every webhook hit can be cryptographically verified before you act on it. The <code>webhook-timestamp<\/code> header is particularly important: best practices call for always validating this timestamp and rejecting payloads older than five minutes to mitigate replay attacks.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Thin Payloads and the Event Catalog<\/strong><\/h3>\n<p>One architectural decision worth noting is the thin payload model. To avoid bandwidth congestion, Gemini webhooks deliver a snapshot containing status details and pointers to results, rather than the raw output file itself. The exact fields in that snapshot depend on the event type.<\/p>\n<p>For batch jobs, a completed notification carries the job <code>id<\/code> and an <code>output_file_uri<\/code> pointing to your results \u2014 for example, a Cloud Storage path like <code>gs:\/\/my-bucket\/results.jsonl<\/code>. For video generation, the <code>video.generated<\/code> event delivers a different set of fields: <code>file_id<\/code> and <code>video_uri<\/code>. Your server-side handler needs to branch on event type before reading the payload data fields.<\/p>\n<p>The full event catalog covers three categories: batch jobs (<code>batch.succeeded<\/code>, <code>batch.cancelled<\/code>, <code>batch.expired<\/code>, <code>batch.failed<\/code>), Interactions API operations (<code>interaction.requires_action<\/code>, <code>interaction.completed<\/code>, <code>interaction.failed<\/code>, <code>interaction.cancelled<\/code>), and video generation (<code>video.generated<\/code>). For developers writing code: the official code samples in Google\u2019s documentation subscribe to and handle <code>batch.completed<\/code> rather than <code>batch.succeeded<\/code> \u2014 both appear across the documentation, so match whichever your implementation uses.<\/p>\n<p>The Interactions API, for readers unfamiliar with it, is Gemini\u2019s API for async multi-turn agent conversations. The <code>interaction.requires_action<\/code> event is particularly useful \u2014 it fires when a function call is pending and your application needs to step in and take an action before the agent can continue.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Delivery Guarantees and Best Practices<\/strong><\/h3>\n<p>Google guarantees \u201cat-least-once\u201d delivery with automatic retries for up to 24 hours using exponential backoff. The \u201cat-least-once\u201d guarantee means your endpoint could occasionally receive the same event more than once under high-congestion conditions. The consistent <code>webhook-id<\/code> header should be used to deduplicate these. Your server should also respond with a <code>2xx<\/code> status code immediately upon valid signature detection and queue any heavier parsing internally \u2014 prolonged listener hold times trigger the retry cycle, which is the opposite of what you want.<\/p>\n<h3 class=\"wp-block-heading\"><strong>Key Takeaways<\/strong><\/h3>\n<ul class=\"wp-block-list\">\n<li><strong>No more polling loops<\/strong> \u2014 The Gemini API now pushes a signed HTTP POST to your server the instant a long-running job (Batch API, Deep Research, video generation) completes, eliminating the need to repeatedly call <code>GET \/operations<\/code>.<\/li>\n<li><strong>Two webhook modes for different architectures<\/strong> \u2014 Static webhooks handle project-level global integrations secured via HMAC; Dynamic webhooks bind to individual job requests via JWKS signatures and support <code>user_metadata<\/code> for custom routing logic in agent-orchestration pipelines.<\/li>\n<li><strong>Security is built in, not bolted on<\/strong> \u2014 Every notification is cryptographically signed per the Standard Webhooks spec using <code>webhook-signature<\/code>, <code>webhook-id<\/code>, and <code>webhook-timestamp<\/code> headers. Reject payloads older than 5 minutes to block replay attacks, and use <code>webhook-id<\/code> to deduplicate at-least-once deliveries.<\/li>\n<li><strong>Thin payloads, not raw results<\/strong> \u2014 Webhook notifications carry status pointers, not output data. Batch events return <code>output_file_uri<\/code>; video events return <code>file_id<\/code> and <code>video_uri<\/code>. Always respond <code>2xx<\/code> immediately and process asynchronously \u2014 slow responses trigger exponential-backoff retries for up to 24 hours.<\/li>\n<\/ul>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n<p>Check out\u00a0the\u00a0<strong><a href=\"https:\/\/blog.google\/innovation-and-ai\/technology\/developers-tools\/event-driven-webhooks\/\" target=\"_blank\" rel=\"noreferrer noopener\">Technical details here<\/a><\/strong>.<strong>\u00a0<\/strong>Also,\u00a0feel free to follow us on\u00a0<strong><a href=\"https:\/\/x.com\/intent\/follow?screen_name=marktechpost\" target=\"_blank\" rel=\"noreferrer noopener\"><mark>Twitter<\/mark><\/a><\/strong>\u00a0and don\u2019t forget to join our\u00a0<strong><a href=\"https:\/\/www.reddit.com\/r\/machinelearningnews\/\" target=\"_blank\" rel=\"noreferrer noopener\">130k+ ML SubReddit<\/a><\/strong>\u00a0and Subscribe to\u00a0<strong><a href=\"https:\/\/www.aidevsignals.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">our Newsletter<\/a><\/strong>. Wait! are you on telegram?\u00a0<strong><a href=\"https:\/\/t.me\/machinelearningresearchnews\" target=\"_blank\" rel=\"noreferrer noopener\">now you can join us on telegram as well.<\/a><\/strong><\/p>\n<p>Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.?\u00a0<strong><a href=\"https:\/\/forms.gle\/MTNLpmJtsFA3VRVd9\" target=\"_blank\" rel=\"noreferrer noopener\"><mark>Connect with us<\/mark><\/a><\/strong><\/p>\n<p>The post <a href=\"https:\/\/www.marktechpost.com\/2026\/05\/05\/google-adds-event-driven-webhooks-to-the-gemini-api-eliminating-the-need-for-polling-in-long-running-ai-jobs\/\">Google Adds Event-Driven Webhooks to the Gemini API, Eliminating the Need for Polling in Long-Running AI Jobs<\/a> appeared first on <a href=\"https:\/\/www.marktechpost.com\/\">MarkTechPost<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>If you\u2019ve ever built a product&hellip;<\/p>\n","protected":false},"author":1,"featured_media":29,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-849","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/posts\/849","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=849"}],"version-history":[{"count":0,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/posts\/849\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/media\/29"}],"wp:attachment":[{"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=849"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=849"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=849"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}