---
title: Callback | RunAPI
description: Ricevi e verifica in modo sicuro le consegne dei callback dei Task.
url: https://runapi.ai/it/docs/guides/task-api/callbacks.md
canonical: https://runapi.ai/it/docs/guides/task-api/callbacks
locale: it
---

> Versione HTML: https://runapi.ai/it/docs/guides/task-api/callbacks
> Indice del sito per gli agenti: https://runapi.ai/llms.txt

# Callback

Usa le callback per ricevere gli eventi del ciclo di vita del Task presso un endpoint HTTPS pubblico. Verifica ogni callback prima di elaborarne il corpo JSON affinché
solo le consegne firmate per il tuo account possano modificare lo stato dell'applicazione.

## Configura un URL di callback

Aggiungi un `callback_url` HTTPS pubblico quando crei un Task. Il corpo dell'evento
e gli stati del ciclo di vita dipendono dall'endpoint; consulta il Riferimento API di quell'endpoint
per i payload di callback.

```json
{
  "model": "flux-2-pro-text-to-image",
  "prompt": "A product photograph on a clean studio background",
  "callback_url": "https://your-domain.com/webhooks/runapi"
}
```

## Creare un Callback Secret

Segui la [Guida all'Autenticazione](https://runapi.ai/it/docs/guides/authentication.md) per accedere,
therefore apri Chiavi API e crea un Segreto Callback per l'account che
crea il Task. Conserva il valore in un gestore di segreti e rendilo
disponibile solo al tuo ricevitore di callback. Non è una Chiave API e non deve
mai essere inviato in una richiesta Task.

Il segreto firma i callback per quell'account. La sua rotazione cambia la
firma per le consegne successive, quindi aggiorna immediatamente ogni ricevitore di callback
e tieni entrambi i valori disponibili solo per il tempo necessario a gestire
le consegne in corso.

## Verifica la firma di una Callback

Ogni callback è un HTTP `POST` con `Content-Type: application/json`.
RunAPI non aggiunge un'intestazione `Authorization` a questa richiesta. Verifica
queste intestazioni prima di deserializzare il corpo:

| Intestazione | Significato |
|----------
| `X-Callback-Id` | Identificatore univoco per questo tentativo di consegna. |
| `X-Callback-Timestamp` | Timestamp Unix in secondi di quando la consegna è stata firmata. |
| `X-Callback-Signature` | Firma HMAC-SHA-256 codificata in Base64. |

Costruisci il valore firmato esattamente come segue, utilizzando i byte del corpo
della richiesta non modificati:

```text
X-Callback-Id + "." + X-Callback-Timestamp + "." + raw request body
```

Decodifica in Base64 il Callback Secret, calcola HMAC-SHA-256 su quel
valore, codifica in Base64 il risultato e confrontalo con
`X-Callback-Signature` usando un confronto a tempo costante. Non analizzare e
ri-serializzare il JSON prima di verificarlo.

### JavaScript

```javascript
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyCallback({headers, rawBody, callbackSecret}) {
  const callbackId = headers["x-callback-id"];
  const timestamp = Number(headers["x-callback-timestamp"]);
  const signature = headers["x-callback-signature"];

  if (!callbackId || !signature || !Number.isSafeInteger(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const signedContent = `${callbackId}.${timestamp}.${rawBody}`;
  const expected = createHmac("sha256", Buffer.from(callbackSecret, "base64"))
    .update(signedContent, "utf8")
    .digest();
  const received = Buffer.from(signature, "base64");

  return expected.length === received.length && timingSafeEqual(expected, received);
}
```

Passa la stringa grezza del corpo della richiesta del framework a `rawBody`; non chiamare
`JSON.stringify` sui dati già analizzati.

### Python

```python
import base64
import hashlib
import hmac
import time


def verify_callback(headers, raw_body, callback_secret):
    callback_id = headers.get("X-Callback-Id")
    timestamp = headers.get("X-Callback-Timestamp")
    signature = headers.get("X-Callback-Signature")

    if not callback_id or not timestamp or not signature:
        return False

    try:
        timestamp = int(timestamp)
        secret = base64.b64decode(callback_secret, validate=True)
        received = base64.b64decode(signature, validate=True)
    except (ValueError, TypeError):
        return False

    if abs(time.time() - timestamp) > 300:
        return False

    signed_content = f"{callback_id}.{timestamp}.{raw_body}".encode("utf-8")
    expected = hmac.new(secret, signed_content, hashlib.sha256).digest()
    return hmac.compare_digest(expected, received)
```

Passa l'esatta stringa grezza del corpo della richiesta ricevuta dal tuo framework HTTP
come `raw_body`.

## Gestire le consegne in modo sicuro

* Restituisci una risposta `2xx` solo dopo che la callback è stata accettata
  per l'elaborazione. In caso di risposta non `2xx` o di errore di
  trasporto, la consegna viene ritentata fino a 10 volte.
* Rispondi entro 15 secondi. Accoda il lavoro più lento dopo la verifica
  anziché bloccare la risposta HTTP.
* Rifiuta le callback prive di intestazioni di firma, con firma non valida
  o con un timestamp al di fuori della finestra di tolleranza definita
  dal tuo ricevitore.

## Risoluzione dei problemi di verifica

* **Mancata corrispondenza della firma:** conferma che il Callback Secret appartenga allo stesso account del Task, decodificalo con Base64 e firma il corpo originale anziché il JSON analizzato.
* **Intestazioni di firma mancanti:** crea un Callback Secret prima di affidarti ai callback per i cambiamenti di stato.
* **Timestamp rifiutato:** sincronizza l'orologio del ricevitore e usa una tolleranza appropriata per il tuo deployment.

Per le istruzioni di configurazione e ciclo di vita, torna alla [Guida introduttiva
all'API Task](https://runapi.ai/it/docs/guides/task-api/quickstart.md).

---

## Altre risorse di RunAPI

- [Home](https://runapi.ai/it/.md)
- [Catalogo dei modelli](https://runapi.ai/it/models.md)
- [Prezzi](https://runapi.ai/it/pricing.md)
- [Fornitori](https://runapi.ai/it/models)
- [Documentazione](https://runapi.ai/it/docs/guides)
- [SDK](https://runapi.ai/it/sdk.md)
- [CLI](https://runapi.ai/it/cli.md)
- [MCP Server](https://runapi.ai/it/mcp.md)
- [Claude Code vs Cursor](https://runapi.ai/it/claude-code-vs-cursor.md)
- [Configurazione Cursor API](https://runapi.ai/it/cursor-api-setup.md)
- [RunAPI vs OpenRouter](https://runapi.ai/it/openrouter-alternative.md)
- [Enterprise](https://runapi.ai/it/contact.md)
- [Contatti](https://runapi.ai/it/contact.md)
- [Termini](https://runapi.ai/it/terms.md)
- [Privacy](https://runapi.ai/it/privacy.md)
- [Indice del sito per gli agenti](https://runapi.ai/llms.txt)

Contatti: contact@runapi.ai

## Dati strutturati

```json
[
  {
    "@context": "https://schema.org",
    "inLanguage": "it",
    "@type": "WebSite",
    "name": "RunAPI",
    "url": "https://runapi.ai/it",
    "potentialAction": {
      "@type": "SearchAction",
      "target": {
        "@type": "EntryPoint",
        "urlTemplate": "https://runapi.ai/it/models?q={search_term_string}"
      },
      "query-input": "required name=search_term_string"
    }
  },
  {
    "@context": "https://schema.org",
    "inLanguage": "it",
    "@type": "Organization",
    "name": "RunAPI",
    "url": "https://runapi.ai/it",
    "logo": {
      "@type": "ImageObject",
      "url": "https://runapi.ai/iticon.svg"
    },
    "sameAs": [
      "https://github.com/runapi-ai"
    ]
  },
  {
    "@context": "https://schema.org",
    "inLanguage": "it",
    "@type": "TechArticle",
    "headline": "Callback",
    "description": "Ricevi e verifica in modo sicuro le consegne dei callback dei Task.",
    "url": "https://runapi.ai/it/docs/guides/task-api/callbacks",
    "mainEntityOfPage": "https://runapi.ai/it/docs/guides/task-api/callbacks"
  }
]
```
