Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Azure webhook OpenAI consentono alle applicazioni di ricevere notifiche in tempo reale sugli eventi API, ad esempio il completamento in batch o le chiamate in ingresso. Sottoscrivendo eventi webhook, è possibile automatizzare i flussi di lavoro, attivare gli avvisi e integrarsi facilmente con altri sistemi. Questa guida illustra come configurare un server webhook, proteggere gli endpoint, distribuire e risolvere i problemi comuni.
Prerequisiti
- interfaccia della riga di comando di Azure è stato installato e l'accesso è avvenuto. Ad esempio:
az --versioneaz login. Vedere https://learn.microsoft.com/cli/azure/install-azure-cli. - Un endpoint di risorsa OpenAI Azure (ad esempio,
https://{resource}.openai.azure.com/) e una chiave API disponibile comeAZURE_OPENAI_API_KEY.
Installare i pacchetti di Python necessari:
pip install flask openai requests
Configurazione del server webhook
Un server webhook è un'applicazione in ascolto dei messaggi automatizzati (webhook) inviati da Azure OpenAI quando si verificano eventi specifici.
Creare l'applicazione listener webhook
Creare un file denominato app.py con l'applicazione Flask seguente che riceve ed elabora eventi webhook:
from flask import Flask, request, Response
from openai import OpenAI, InvalidWebhookSignatureError
import os
import logging
app = Flask(__name__)
# Configure logging for Azure App Service
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
client = OpenAI(
# api-key parameter is required, but If you are only using the client for webhooks the key can be a placeholder string
api_key=os.environ.get("OPENAI_API_KEY", "placeholder-key-for-webhooks-only"),
webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"] # This will be created later
)
@app.route("/webhook", methods=["POST"])
def webhook():
"""Webhook endpoint to receive and process OpenAI events."""
try:
# Unwrap and verify the message using the webhook secret
event = client.webhooks.unwrap(request.data, request.headers)
# Process the event based on type
if event.type == "realtime.call.incoming":
logger.info(f"Received a realtime.call.incoming message for call_id = {event.data.call_id}")
# Add your custom logic here:
# - Log the call details
# - Trigger notifications
# - Update databases
# - Start call processing workflows
elif event.type == "response.completed":
logger.info(f"Received a response.completed message")
# Add your custom logic here
else:
logger.info(f"Received unexpected message of type = {event.type}")
# Always return 200 to acknowledge receipt
return Response(status=200)
except InvalidWebhookSignatureError as e:
logger.error(f"Invalid signature: {e}")
return Response("Invalid signature", status=400)
except Exception as e:
logger.error(f"Error processing webhook: {e}")
return Response("Internal server error", status=500)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8000, debug=True)
Creare un file di requirements.txt
Creare un file requirements.txt nella stessa directory del file app.py.
flask
openai
requests
Creare un'app Web Azure
Distribuire il server webhook usando az webapp up. Il comando deve essere eseguito dalla cartella in cui si trova il codice per l'applicazione app.py .
az webapp up --name unique-webhook-handler-name --resource-group myResourceGroup --runtime "PYTHON:3.12"
Questo comando farà:
- Creare un gruppo di risorse se non esiste.
- Creare un App Service Plan.
- Creare un'app Web.
- Distribuite il vostro codice.
L'URL del webhook sarà: https://unique-webhook-handler-name.azurewebsites.net/webhook
Creare un endpoint webhook
Gli endpoint webhook di Azure OpenAI devono essere creati usando l'API REST. Registrare il listener per ricevere eventi webhook per tipi di evento specifici.
import requests
import json
import os
AZURE_OPENAI_API_KEY = os.environ.get("AZURE_OPENAI_API_KEY")
WEBHOOK_NAME = "<WEBHOOK-NAME>" # Give your webhook a custom name
WEBHOOK_URL = "<YOUR-URL>/webhook" # e.g., "https://unique-webhook-handler-name.azurewebsites.net/webhook"
url = "https://<YOUR_RESOURCE_NAME>.openai.azure.com/openai/v1/dashboard/webhook_endpoints"
headers = {
"api-key": AZURE_OPENAI_API_KEY,
"Content-Type": "application/json"
}
data = {
"name": WEBHOOK_NAME,
"url": WEBHOOK_URL,
"event_types": ["response.completed"]
}
response = requests.post(url, headers=headers, json=data)
print(json.dumps(response.json(), indent=2))
Importante
Il segreto di firma viene visualizzato una sola volta durante la creazione. I segreti possono essere archiviati in modo sicuro usando Azure Key Vault.
Configurare il segreto webhook in Azure'app Web
Impostare il segreto di firma webhook come variabile di ambiente nell'app Web Azure:
az webapp config appsettings set --name unique-webhook-handler-name \
--resource-group myResourceGroup \
--settings OPENAI_WEBHOOK_SECRET="<YOUR-SIGNING-SECRET-GOES-HERE>"
Dopo aver impostato la variabile di ambiente, riavviare l'app Web:
az webapp restart --name unique-webhook-handler-name --resource-group myResourceGroup
Test dei messaggi webhook
Per prima cosa, conferma che la tua app Web ha completato il riavvio controllando lo stream di log.
az webapp log tail --name unique-webhook-handler-name --resource-group myResourceGroup
Al termine del riavvio, è possibile testare l'endpoint del webhook inviando eventi dell'API REST di esempio.
import requests
import time
import json
WEBHOOK_URL = "https://<unique-webhook-handler-name>.azurewebsites.net/webhook"
TEST_TIMESTAMP = int(time.time())
headers = {
"Content-Type": "application/json",
"Webhook-ID": "test-id",
"Webhook-Timestamp": str(TEST_TIMESTAMP),
"Webhook-Signature": "test-signature"
}
payload = {
"object": "event",
"id": "test-event",
"type": "response.completed",
"created_at": TEST_TIMESTAMP,
"data": {
"call_id": "test-call",
"sip_headers": []
}
}
try:
# timeout in seconds (connect timeout, read timeout)
response = requests.post(WEBHOOK_URL, headers=headers, json=payload, timeout=(5, 30))
print(f"Status Code: {response.status_code}")
print(f"Response: {response.text}")
except requests.exceptions.Timeout:
print("Request timed out!")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
Nota
La firma di test iniziale non supererà la convalida. Per i test di produzione, è possibile attivare eventi effettivi da Azure OpenAI con firme valide.
Ora avvia il flusso di log per la tua web app listener del webhook, se non è già in esecuzione.
az webapp log tail --name unique-webhook-handler-name --resource-group myResourceGroup
Per eseguire di nuovo il test con una firma valida, effettuare una chiamata all'API di risposta con background=True configurato.
from openai import OpenAI
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
token_provider = get_bearer_token_provider(
DefaultAzureCredential(), "https://ai.azure.com/.default"
)
client = OpenAI(
base_url = "https://<YOUR-RESOURCE-NAME>.openai.azure.com/openai/v1/",
api_key=token_provider,
)
resp = client.responses.create(
model="o4-mini",
input="Write a very long novel about otters in space.",
background=True,
)
print(resp.status)
Python output:
queued
Output del flusso di log:
2025-10-24T23:40:23.623889430Z INFO:app:Received a response.completed message
Procedure consigliate per la sicurezza
La protezione dell'endpoint del webhook è fondamentale. Seguire queste raccomandazioni:
Verifica della firma
Verificare sempre la firma del webhook per assicurarsi che le richieste provengano da Azure OpenAI:
try:
event = client.webhooks.unwrap(request.data, request.headers)
except InvalidWebhookSignatureError:
return Response("Invalid signature", status=400)
Idempotenza
Usare l'intestazione Webhook-ID per impedire l'elaborazione duplicata:
webhook_id = request.headers.get('Webhook-ID')
if webhook_id in processed_webhooks:
return Response(status=200) # Already processed
Gestione del timeout
Rispondere rapidamente per evitare i timeout del webhook. Scarica il processamento pesante su thread in background.
def process_call_async(call_data):
# Your heavy processing here
pass
# In webhook handler:
threading.Thread(target=process_call_async, args=(event.data,)).start()
return Response(status=200)
Suggerimenti aggiuntivi
- Archiviare il segreto di firma in modo sicuro; viene visualizzato una sola volta durante la creazione.
- Usare HTTPS per tutti gli endpoint webhook.
- Proteggere e ruotare regolarmente i token di accesso Azure.
- Convalidare le richieste in ingresso usando il segreto di firma.
Esempi di elaborazione di eventi
Ecco alcuni modelli comuni per l'elaborazione di eventi webhook:
Registrazione delle chiamate
if event.type == "realtime.call.incoming":
call_data = {
'call_id': event.data.call_id,
'timestamp': event.created_at,
'from': next((h['value'] for h in event.data.sip_headers if h['name'] == 'From'), None),
'to': next((h['value'] for h in event.data.sip_headers if h['name'] == 'To'), None)
}
# Log to database or file
log_call(call_data)
Sistema di notifica
if event.type == "realtime.call.incoming":
# Send notification to monitoring system
send_notification({
'type': 'incoming_call',
'call_id': event.data.call_id,
'caller': get_caller_from_headers(event.data.sip_headers)
})
Gestione degli endpoint webhook
Elencare gli endpoint del webhook
curl -X GET https://<YOUR-RESOURCE-NAME>.openai.azure.com/openai/v1/dashboard/webhook_endpoints \
-H "api-key: $AZURE_OPENAI_API_KEY" \
-H "Content-Type: application/json"
Aggiornare l'endpoint del webhook
Nota
Aggiornare le proprietà del webhook, ad esempio nome, URL e tipi di evento registrati. Non è possibile aggiornare il segreto di firma tramite questa operazione.
curl -X POST https://<YOUR-RESOURCE-NAME>.openai.azure.com/openai/v1/dashboard/webhook_endpoints/<webhook_id> \
-H "api-key: $AZURE_OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "<UpdatedName>",
"url": "<UpdatedURL>",
"event_types": [
"response.completed",
"response.failed",
"realtime.call.incoming"
]
}'
Eliminare l'endpoint del webhook
Rimuovere un endpoint webhook usando il relativo ID webhook:
curl -X DELETE https://<YOUR-RESOURCE-NAME>.openai.azure.com/openai/v1/dashboard/webhook_endpoints/<webhook_id> \
-H "api-key: $AZURE_OPENAI_API_KEY" \
-H "Accept: application/json"
Problemi comuni e risoluzione dei problemi
| Problema | Soluzione |
|---|---|
| Firma non valida | Verificare che il OPENAI_WEBHOOK_SECRET sia corretto e corrisponda al segreto fornito durante la creazione. |
| Timeouts | Mantenere l'elaborazione del webhook in meno di 10 secondi; usare le attività in background per operazioni pesanti. |
| Eventi mancanti | Assicurarsi che l'endpoint sia accessibile pubblicamente e usi HTTPS. Monitorare i tentativi di recapito nei log di Azure. |
Gestione delle richieste webhook in un server
Quando si verifica un evento a cui si è iscritti, si riceverà una richiesta POST con la struttura seguente:
POST https://my-webhook-handler.azurewebsites.net/webhook
User-Agent: OpenAI/1.0 (+https://platform.openai.com/docs/webhooks)
Content-Type: application/json
Webhook-ID: <webhook_eventid>
Webhook-Timestamp: 1750287078
Webhook-Signature: v1,Sample Signature
{
"object": "event",
"id": "evt_685343a1381c819085d44c354e1b330e",
"type": "realtime.call.incoming",
"created_at": 1750287018,
"data": {
"call_id": "some_unique_id",
"sip_headers": [
{
"name": "From",
"value": "sip:+142555512112@sip.example.com"
},
{
"name": "To",
"value": "sip:+18005551212@sip.example.com"
},
{
"name": "Call-ID",
"value": "rtc_9d3d08ea002a4909813d207a592957c4"
}
]
}
}
Intestazione
-
Webhook-ID: identificatore univoco per idempotenza: usare questa opzione per impedire l'elaborazione duplicata -
Webhook-Timestamp: Timestamp Unix del tentativo di recapito -
Webhook-Signature: firma crittografica per verificare l'autenticità da OpenAI
Payload
-
object: sempre "event" per gli eventi webhook -
id: identificatore di evento univoco -
type: tipo di evento (ad esempio, "realtime.call.incoming") -
created_at: timestamp Unix al momento della creazione dell'evento -
data: dati specifici dell'evento contenenti informazioni sulle chiamate e intestazioni SIP
Informazioni di riferimento sugli eventi webhook
Per la registrazione del webhook sono disponibili i tipi di evento seguenti:
| Categoria | Tipo di evento | Descrizione |
|---|---|---|
| Eventi di risposta | response.completed |
Risposta completata |
response.failed |
Risposta non riuscita | |
response.cancelled |
Risposta annullata | |
response.incomplete |
Risposta incompleta | |
| Eventi batch | batch.completed |
Batch completato correttamente |
batch.failed |
Batch non riuscito | |
batch.cancelled |
Batch annullato | |
batch.expired |
Batch scaduto | |
| Ottimizzazione degli eventi | fine_tuning.job.succeeded |
Processo di ottimizzazione completata |
fine_tuning.job.failed |
Processo di ottimizzazione non riuscito | |
fine_tuning.job.cancelled |
Processo di rifinitura annullato | |
| Eventi in tempo reale | realtime.call.incoming |
Evento di chiamata in ingresso |
Payload di esempio
{
"object": "event",
"id": "evt_685343a1381c819085d44c354e1b330e",
"type": "realtime.call.incoming",
"created_at": 1750287018,
"data": {
"call_id": "some_unique_id",
"sip_headers": [
{ "name": "From", "value": "sip:+142555512112@sip.example.com" },
{ "name": "To", "value": "sip:+18005551212@sip.example.com" },
{ "name": "Call-ID", "value": "rtc_9d3d08ea002a4909813d207a592957c4" }
]
}
}
Pulire le risorse
Quando il server webhook non è più necessario, è possibile eliminare l'app Web Azure e le relative risorse associate.
Eliminare solo l'app Web
Per eliminare solo l'app Web mantenendo il gruppo di risorse e altre risorse:
az webapp delete --name unique-webhook-handler-name --resource-group myResourceGroup
Configurazioni aggiuntive suggerite
- Implementare la registrazione e il monitoraggio appropriati per gli eventi webhook.
- Aggiungere l'archiviazione del database per i record delle chiamate.
- Configurare gli avvisi per gli invii di webhook non riusciti.
- Implementare la logica di ripetizione dei tentativi per le chiamate al servizio a valle.
- Aggiungere l'autenticazione per l'endpoint del webhook, se necessario.