الويب هوك

تسمح الويب هوك لواجهة برمجة التطبيقات 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.succeeded", "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.succeeded", "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: $GEMINI_API_KEY" \
  -d '{
    "name": "MyBatchWebhook",
    "uri": "https://my-api.com/gemini-callback",
    "subscribed_events": ["batch.succeeded", "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: $GEMINI_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: $GEMINI_API_KEY"

تعديل ويب هوك

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

Python

from google import genai

client = genai.Client()

updated_webhook = client.webhooks.update(
    id="<your_webhook_id>",
    subscribed_events=["batch.succeeded", "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.succeeded", "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: $GEMINI_API_KEY" \
  -d '{
    "subscribed_events": ["batch.succeeded", "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: $GEMINI_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: $GEMINI_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") == "batch.succeeded":
        print(f"Batch completed! ID: {event['data']['id']}")
        if event["data"].get("output_file_uri"):
            # For batch jobs with input file
            print(f"Batch file: {event['data']['output_file_uri']}")
    elif event.get("type") == "interaction.completed":
        print(f"Interaction completed! ID: {event['data']['id']}")
    elif event.get("type") == "video.generated":
        print(f"Video generated! URI: {event['data']['output_file_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>;
    console.log(`Event type: ${event.type}, data: ${JSON.stringify(event.data)}`);

            // Process thin payload contents
            if (event.type === "batch.succeeded") {
                console.log(`Batch completed! ID: ${event.data.id}`);
                if (event.data.output_file_uri) {
                    // For batch jobs with input file
                    console.log(`Batch file: ${event.data.output_file_uri}`);
                }
            } else if (event.type === "interaction.completed") {
                console.log(`Interaction completed! ID: ${event.data.id}`);
            } else if (event.type === "video.generated") {
                console.log(`Video generated! URI: ${event.data.output_file_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

client = genai.Client()

response = client.interactions.create(
    model='gemini-3-flash-preview',
    input='Tell me a short joke about programming.',
    background=True, # Required when webhook_config is specified
    webhook_config={
        'uris': ["https://my-api.com/gemini-webhook-dynamic"],
        'user_metadata': {"job_group": "nightly-eval", "priority": "high"}
    }
)

print(f"Interaction created! ID: {response.id}")
print(f"Status: {response.status}")

JavaScript

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

const client = new GoogleGenAI();

async function createInteractionWithWebhook() {
  const response = await client.interactions.create({
    model: "gemini-3-flash-preview",
    input: "Tell me a short joke about programming.",
    background: true, // Required when webhook_config is specified
    webhook_config: {
      uris: ["https://my-api.com/gemini-webhook-dynamic"],
      user_metadata: { job_group: "nightly-eval", priority: "high" },
    },
  });

  console.log(`Interaction created! ID: ${response.id}`);
  console.log(`Status: ${response.status}`);
}

createInteractionWithWebhook();

REST

curl -X POST \
  "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -d '{
    "model": "gemini-3-flash-preview",
    "input": "Tell me a short joke about programming.",
    "background": true,
    "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.succeeded",
  "version": "v1",
  "timestamp": "2026-01-22T12:00:00Z",
  "data": {
    "id": "batch_123456",
    "output_file_uri": "gs://my-bucket/results.jsonl"
  }
}

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

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

نوع الحدث 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) لإنشاء الفيديو. id وoutput_file_uri وfile_name

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

لضمان عملية موثوقة وقابلة للتطوير:

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

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

  • Batch API: يمكنك استخدام الويب هوك لأتمتة نقاط النهاية ذات الحجم الكبير.