الردّ التلقائي على الويب

تسمح الويب هوك لواجهة برمجة التطبيقات Gemini API بإرسال إشعارات في الوقت الفعلي إلى خادمك عند اكتمال العمليات غير المتزامنة أو العمليات الطويلة الأمد (LRO). ويحلّ ذلك محل الحاجة إلى طلب البيانات من واجهة برمجة التطبيقات لمعرفة آخر الأخبار، ما يقلّل من وقت الاستجابة والعبء.

تتوفّر الويب هوك لعمليات مثل مهام الدفعات، التفاعلات وإنشاء الفيديوهات.

آلية العمل

بدلاً من طلب البيانات من GET /operations بشكل متكرّر لمعرفة ما إذا كانت مهمة معيّنة قد اكتملت، يمكنك ضبط الويب هوك في Gemini API لإرسال طلب HTTP POST إلى عنوان URL الخاص بالمتتبِّع فور تفعيل مشغِّل حدث معيّن.

تتيح Gemini API طريقتَين لضبط الويب هوك:

  • الويب هوك الثابتة: نقاط نهاية على مستوى المشروع تم ضبطها باستخدام واجهة برمجة التطبيقات Gemini WebhookService API. وهي مناسبة لعمليات التكامل العالمية (مثل إرسال إشعار إلى Slack أو مزامنة قاعدة بيانات أو غير ذلك).
  • الويب هوك الديناميكية: عمليات إلغاء على مستوى الطلب تمرِّر رابط ويب هوك في حمولة الإعدادات لطلب مهام معيّنة. وهي مثالية لتوجيه مهام معيّنة إلى نقاط نهاية مخصّصة.

الويب هوك الثابتة

يتم تسجيل الويب هوك الثابتة لمشروع كامل project ويتم تفعيلها لأي حدث مطابق event.

إنشاء ويب هوك

يمكنك إنشاء نقاط نهاية باستخدام حزمة تطوير البرامج (SDK) أو واجهة برمجة تطبيقات REST.

ملاحظة مهمة: عند إنشاء ويب هوك، تعرض واجهة برمجة التطبيقات سرًا للتوقيع مرة واحدة فقط. عليك تخزين هذا السر بشكل آمن (مثلًا في متغيّرات البيئة) للتحقّق من التوقيعات لاحقًا. إذا فقدت سر التوقيع، عليك تدويره rotate.

Python

from google import genai

client = genai.Client()

webhook = client.webhooks.create(
    name="MyBatchWebhook",
    subscribed_events=["batch.completed", "batch.failed"],
    uri="https://my-api.com/gemini-callback",
)

# Store webhook.new_signing_secret securely
webhook_secret = webhook.new_signing_secret
print(f"Created webhook: {webhook.name}, {webhook.id}")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI();

async function createWebhook() {
  const webhook = await client.webhooks.create({
    name: "MyBatchWebhook",
    subscribed_events: ["batch.completed", "batch.failed"],
    uri: "https://my-api.com/gemini-callback",
  });

  // Store webhook.signingSecret securely
  const webhookSecret = webhook.new_signing_secret;
  console.log(`Created webhook: ${webhook.name}, ${webhook.id}`);
}

createWebhook();

REST

curl -X POST \
  "https://generativelanguage.googleapis.com/v1/webhooks" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GOOGLE_API_KEY" \
  -d '{
    "name": "MyBatchWebhook",
    "uri": "https://my-api.com/gemini-callback",
    "subscribed_events": ["batch.completed", "batch.failed"]
  }'

للحصول على تفاصيل حول إعداد خادمك لتلقّي البيانات، يُرجى الاطّلاع على قسم معالجة طلبات الويب هوك.

الحصول على ويب هوك

يمكنك استرداد تفاصيل حول ويب هوك معيّنة من خلال اسم المورد.

Python

from google import genai

client = genai.Client()

webhook = client.webhooks.get(id="<your_webhook_id>")

print(f"Webhook: {webhook.name}")
print(f"URI: {webhook.uri}")
print(f"Events: {webhook.subscribed_events}")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI(); // Assumes process.env.GEMINI_API_KEY is set

async function getWebhook() {
  const webhook = await client.webhooks.get("<your_webhook_id>");

  console.log(`Webhook: ${webhook.name}`);
  console.log(`URI: ${webhook.uri}`);
  console.log(`Events: ${webhook.subscribed_events}`);
}

getWebhook();

REST

curl -X GET \
  "https://generativelanguage.googleapis.com/v1/webhooks/<your_webhook_id>" \
  -H "x-goog-api-key: $GOOGLE_API_KEY"

سرد الويب هوك

يمكنك سرد جميع الويب هوك التي تم ضبطها للمشروع الحالي، مع إمكانية استخدام الترقيم الاختياري للصفحات.

Python

from google import genai

client = genai.Client()

webhooks = client.webhooks.list()

for wh in webhooks:
    print(f"{wh.id}: {wh.name} -> {wh.uri}")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI();

async function listWebhooks() {
  const webhooks = await client.webhooks.list();

  for (const wh of webhooks) {
    console.log(`${wh.id}: ${wh.name} -> ${wh.uri}`);
  }
}

listWebhooks();

REST

curl -X GET \
  "https://generativelanguage.googleapis.com/v1/webhooks" \
  -H "x-goog-api-key: $GOOGLE_API_KEY"

تعديل ويب هوك

يمكنك تعديل خصائص ويب هوك حالية، مثل الاسم المعروض أو عنوان URI المستهدَف أو الأحداث التي تم الاشتراك فيها.

Python

from google import genai

client = genai.Client()

updated_webhook = client.webhooks.update(
    id="<your_webhook_id>",
    subscribed_events=["batch.completed", "batch.failed", "batch.cancelled"],
)

print(f"Updated webhook: {updated_webhook.name}")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI();

async function updateWebhook() {
  const updatedWebhook = await client.webhooks.update(
    "<your_webhook_id>",
    {
      subscribed_events: ["batch.completed", "batch.failed", "batch.cancelled"],
    }
  );

  console.log(`Updated webhook: ${updatedWebhook.name}`);
}

updateWebhook();

REST

curl -X PATCH \
  "https://generativelanguage.googleapis.com/v1/webhooks/<your_webhook_id>" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GOOGLE_API_KEY" \
  -d '{
    "subscribed_events": ["batch.completed", "batch.failed", "batch.cancelled"]
  }'

حذف ويب هوك

يمكنك إزالة نقطة نهاية ويب هوك من المشروع. وسيؤدي ذلك إلى إيقاف عمليات تسليم الأحداث المستقبلية إلى نقطة النهاية هذه.

Python

from google import genai

client = genai.Client()

client.webhooks.delete(id="<your_webhook_id>")

print("Webhook deleted.")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI();

async function deleteWebhook() {
  await client.webhooks.delete("<your_webhook_id>");

  console.log("Webhook deleted.");
}

deleteWebhook();

REST

curl -X DELETE \
  "https://generativelanguage.googleapis.com/v1/webhooks/<your_webhook_id>" \
  -H "x-goog-api-key: $GOOGLE_API_KEY"

تدوير سر التوقيع

يمكنك تدوير سر التوقيع لويب هوك. ويمكنك تحديد ما إذا كان سيتم إبطال الأسرار النشطة سابقًا على الفور أو بعد فترة سماح مدتها 24 ساعة.

ملاحظة مهمة: يتم عرض سر التوقيع الجديد مرة واحدة فقط في وقت التدوير. عليك تخزينه بشكل آمن قبل تعديل منطق التحقّق.

Python

from google import genai
from google.genai import types

client = genai.Client()

response = client.webhooks.rotate_signing_secret(
    id="<your_webhook_id>",
    revocation_behavior="REVOKE_PREVIOUS_SECRETS_AFTER_H24",
)

# Store response.secret securely, then update your server's verification config
print("New signing secret generated. Update your server configuration.")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI();

async function rotateSigningSecret() {
  const response = await client.webhooks.rotateSigningSecret(
    "<your_webhook_id>",
    {
      revocation_behavior: "REVOKE_PREVIOUS_SECRETS_AFTER_H24",
    }
  );

  // Store response.secret securely, then update your server's verification config
  console.log("New signing secret generated. Update your server configuration.");
}

rotateSigningSecret();

REST

curl -X POST \
  "https://generativelanguage.googleapis.com/v1/webhooks/<your_webhook_id>/rotate_secret" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GOOGLE_API_KEY" \
  -d '{
    "revocation_behavior": "REVOKE_PREVIOUS_SECRETS_AFTER_H24"
  }'

معالجة طلبات الويب هوك على خادم

عند وقوع حدث اشتركت فيه، سيتلقّى رابط ويب هوك الخاص بك طلب HTTP POST. يجب أن تستجيب نقطة النهاية برمز حالة 2xx في غضون بضع ثوانٍ لتجنُّب إعادة المحاولة. لضمان التسليم، تعيد Gemini API تلقائيًا محاولة إرسال الطلبات التي فشلت لمدة 24 ساعة باستخدام التراجع الدليلي.

تتّبع Gemini بدقة مواصفات الويب هوك العادية لـ عناوين الأمان. عليك التحقّق من الحمولة على خادمك باستخدام توقيعات العناوين المُوقَّعة وسر التوقيع الثابت المخزَّن. يمكنك الاطّلاع على قسم غلاف الويب هوك للحصول على معلومات الحمولة.

إليك مثال على استخدام Flask للمستمع HTTP:

Python

# pip install flask standardwebhooks
import os
from flask import Flask, request, jsonify
# Standard verification wrapper for Standard Webhook Headers
from standardwebhooks.webhooks import Webhook, WebhookVerificationError

app = Flask(__name__)

SIGNING_SECRET = os.environ.get('WEBHOOK_SIGNING_SECRET')

@app.route('/gemini-callback', methods=['POST'])
def gemini_callback():
    payload = request.get_data(as_text=True)
    headers = request.headers

    try:
        wh = Webhook(SIGNING_SECRET)
        event = wh.verify(payload, headers)
    except WebhookVerificationError as e:
        return jsonify({"error": "Signature invalid"}), 400

    # Process thin payload contents
    if event.get("type") in ("batch.completed", "video.generated"):
        uri = event['data']['output_file_uri']
        print(f"Batch finished! Results at: {uri}")

    return jsonify({"status": "received"}), 200

if __name__ == "__main__":
    app.run(port=8000)

JavaScript

// npm install standardwebhooks
import { Webhook } from "standardwebhooks";
import express from "express";

const app = express();
const client = new GoogleGenAI({ webhookSecret: process.env.WEBHOOK_SIGNING_SECRET });

// Don't use express.json() because signature verification needs the raw text body
app.use(express.text({ type: "application/json" }));

app.post("/gemini-callback", async (req, res) => {
  const payload = await req.text();
        const headers: Record<string, string> = {};
        req.headers.forEach((value, key) => {
            headers[key] = value;
        });

        try {
            const wh = new Webhook(process.env.WEBHOOK_SIGNING_SECRET);
            const event = wh.verify(payload, headers) as Record<string, any>;

            // Process thin payload contents
            if (event.type === "batch.completed" || event.type === "video.generated") {
                const uri = event.data.output_file_uri;
                console.log(`Job finished! Results at: ${uri}`);
            }

            res.status(200).json({ status: "received" });
        } catch (e) {
            console.error("Webhook verification failed:", e);
            res.status(400).send("Invalid signature");
        }
});

app.listen(8000, () => {
  console.log("Webhook server is running on port 8000");
});

الويب هوك الديناميكية

تسمح لك الويب هوك الديناميكية بربط نقطة نهاية ويب هوك بـ إعداد طلب معيّن، ما يجعلها مثالية لقوائم انتظار تنسيق الوكلاء. تستخدِم الويب هوك الديناميكية توقيعات JWKS غير المتماثلة للمفتاح العام بدلاً من الأسرار المتماثلة.

إرسال طلب ديناميكي

يمكنك إضافة webhook_config عند تفعيل مهمة غير متزامنة (مثل إنشاء دفعة).

Python

from google import genai
from google.genai import types

client = genai.Client()

file_batch_job = client.batches.create(
    model="gemini-3-flash-preview",
    src="files/uploaded_file_id",
    config={
        "display_name": "My Setup",
        "webhook_config": {
            "uris": ["https://my-api.com/gemini-webhook-dynamic"],
            "user_metadata":{"job_group": "nightly-eval", "priority": "high"}
        }
    }
)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI();

async function createBatchWithWebhook() {
  const fileBatchJob = await client.batches.create({
    model: "gemini-3-flash-preview",
    src: "files/uploaded_file_id",
    config: {
      displayName: "My Setup",
      webhookConfig: {
        uris: ["https://my-api.com/gemini-webhook-dynamic"],
        user_metadata: {"job_group": "nightly-eval", "priority": "high"}
      },
    },
  });
}

REST

curl -X POST \
  "https://generativelanguage.googleapis.com/v1/models/gemini-3-flash-preview:batchCreate" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GOOGLE_API_KEY" \
  -d '{
    "src": "files/uploaded_file_id",
    "config": {
      "display_name": "My Setup",
      "webhook_config": {
        "uris": ["https://my-api.com/gemini-webhook-dynamic"],
        "user_metadata": {"job_group": "nightly-eval", "priority": "high"}
      }
    }
  }'

التحقّق من التوقيعات الديناميكية (JWKS)

تُصدر طلبات الويب هوك الديناميكية توقيع رمز JSON المميّز للويب (JWT). على المستمع استخراج التوقيع والتحقّق منه باستخدام نقاط نهاية الشهادات العامة من Google .

Python

import jwt
import requests
from flask import Flask, request, jsonify

app = Flask(__name__)

# Google public cert list endpoint
JWKS_URI = "https://generativelanguage.googleapis.com/.well-known/jwks.json"

def load_google_public_key(kid):
    response = requests.get(JWKS_URI).json()
    for key_item in response.get('keys', []):
        if key_item.get('kid') == kid:
            # Convert JWK to Cert wrapper
            return jwt.algorithms.RSAAlgorithm.from_jwk(key_item)
    return None

@app.route('/gemini-webhook-dynamic', methods=['POST'])
def dynamic_handler():
    payload = request.get_data(as_text=True)
    headers = request.headers

    token = headers.get('Webhook-Signature')
    if not token:
        return jsonify({"error": "No signature header"}), 400

    try:
        # Extract kid from JWT header
        unverified_headers = jwt.get_unverified_header(token)
        pub_key = load_google_public_key(unverified_headers.get('kid'))

        if not pub_key:
            return jsonify({"error": "Key cert not found"}), 400

        # Verify Signature against expected audience (e.g., your project client ID)
        event = jwt.decode(
            token,
            pub_key,
            algorithms=["RS256"],
            audience="your-configured-audience"
        )
    except Exception as e:
        return jsonify({"error": "Invalid Dynamic signature", "details": str(e)}), 400

    print("Verified Dynamic payload success.")
    return jsonify({"status": "received"}), 200

JavaScript

import { GoogleGenAI } from "@google/genai";
import express from "express";
import jwt from "jsonwebtoken";
import jwksClient from "jwks-rsa";

const app = express();
app.use(express.text({ type: 'application/json' }));

const client = jwksClient({
  jwksUri: "https://generativelanguage.googleapis.com/.well-known/jwks.json"
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    const signingKey = key.getPublicKey();
    callback(null, signingKey);
  });
}

app.post('/gemini-webhook-dynamic', (req, res) => {
  const token = req.headers['webhook-signature'];

  if (!token) {
    return res.status(400).json({ error: "No signature header" });
  }

  jwt.verify(
    token,
    getKey,
    {
      algorithms: ["RS256"],
      audience: "your-configured-audience"
    },
    (err, decoded) => {
      if (err) {
        return res.status(400).json({ error: "Invalid Dynamic signature", details: err.message });
      }

      console.log("Verified Dynamic payload success.");
      res.status(200).json({ status: "received" });
    }
  );
});

غلاف الويب هوك

لتجنُّب ازدحام النطاق الترددي، تستخدِم الويب هوك في Gemini نموذج حمولة صغيرة لتسليم البيانات. وترسل عمليات التسليم لقطة تحتوي على تفاصيل الحالة ومؤشرات إلى النتائج، بدلاً من ملف الإخراج الأولي نفسه.

في ما يلي مثال على تنسيق الحمولة:

{
  "type": "batch.completed",
  "version": "v1",
  "timestamp": "2026-01-22T12:00:00Z",
  "data": {
    "id": "batch_123456",
    "output_file_uri": "gs://my-bucket/results.jsonl",
    "error_count": 0
  }
}

مرجع كتالوج الأحداث

يتم تفعيل الأحداث التالية للوظائف المتوافقة:

نوع الحدث Trigger عنصر الحمولة (data)
batch.succeeded اكتملت المعالجة بنجاح. id وoutput_file_uri
batch.cancelled ألغى المستخدم الطلب id
batch.expired لم تتم معالجة الدفعة (اكتملت) خلال فترة 24 ساعة id
batch.failed فشلت مهمة الدفعة (حدث خطأ في النظام أو التحقّق من الصحة). id وerror_code وerror_message
interaction.requires_action استدعاء الدالة، على المستخدم اتّخاذ إجراء id
interaction.completed اكتملت العملية الطويلة الأمد (LRO) في واجهة برمجة التطبيقات Interactions API بنجاح id
interaction.failed فشلت العملية الطويلة الأمد (LRO) في واجهة برمجة التطبيقات Interactions API (حدث خطأ في النظام أو التحقّق من الصحة). id وerror_code وerror_message
interaction.cancelled تم إلغاء العملية الطويلة الأمد (LRO) في واجهة برمجة التطبيقات Interactions API id
video.generated اكتملت العملية الطويلة الأمد (LRO) لإنشاء الفيديو. file_id وvideo_uri

أفضل الممارسات

لضمان عملية موثوقة وقابلة للتوسّع:

  • التحقّق الدقيق من الحماية من إعادة التشغيل: تحمل جميع الطلبات webhook-timestamp عنوان. عليك دائمًا التحقّق من هذا الطابع الزمني على طبقة إعدادات الخادم لرفض الحمولات التي يزيد عمرها عن 5 دقائق (للتخفيف من هجمات إعادة التشغيل).
  • المعالجة غير المتزامنة: عليك الردّ باستخدام 2xx OK فور رصد توقيع صالح ، ووضع عمليات التحليل في قائمة الانتظار داخليًا. ستؤدي فترات الانتظار الطويلة للمستمع إلى تفعيل دورة إعادة محاولة التسليم.
  • معالجة إزالة التكرار: تُسلّم الويب هوك العادية البيانات "مرة واحدة على الأقل". استخدِم عنوان webhook-id المتسق لمعالجة أي تكرارات محتملة في تدفقات الازدحام الأعلى.

ما هي الخطوات التالية؟