Blog

API di Facebook Messenger: Crea Esperienze Conversazionali

Scopri come creare chatbot con l'API di Facebook Messenger. Guida completa su webhook, modelli di messaggio, risposte rapide e messaggi multimediali.

Di

+8

Pubblica ovunque. Una API.

Try Free

L'API di Facebook Messenger consente agli sviluppatori di creare esperienze conversazionali che raggiungono oltre 1,3 miliardi di utenti attivi mensili. Che tu stia creando un bot per l'assistenza clienti, un assistente per l'e-commerce o una campagna di marketing interattiva, l'API della piattaforma Messenger offre gli strumenti necessari per coinvolgere gli utenti in conversazioni significative.

Questa guida ti accompagnerà attraverso tutto, dalla configurazione iniziale a funzionalità avanzate come i modelli di messaggio, le risposte rapide e il protocollo di passaggio umano. Troverai esempi pratici in TypeScript, pronti per essere adattati ai tuoi progetti.

Introduzione alla Piattaforma Messenger

La piattaforma Messenger è il framework di Meta per costruire bot e integrazioni che comunicano con gli utenti tramite Facebook Messenger. A differenza delle interfacce web tradizionali, l'API di chat di Facebook crea un'esperienza conversazionale in cui gli utenti interagiscono tramite messaggi, pulsanti e contenuti multimediali.

Le principali funzionalità dell'API del bot per messaggistica includono:

FeatureDescriptionCaso d'uso
Messaggi di testoInvio e ricezione di messaggi di baseRichieste dei clienti, notifiche
Modelli di MessaggioLayout strutturati con immagini e pulsantiCataloghi prodotti, ricevute
Risposte VelociPulsanti di risposta suggeritiConversazioni guidate, sondaggi
Menu PersistenteOpzioni di navigazione sempre disponibiliNavigazione del bot, azioni comuni
Messaggi MultimedialiImmagini, video, audio e fileImmagini del prodotto, tutorial
Protocollo di PassaggioTrasferimento tra bot e agenti umaniEscalazione complessa del supporto

La piattaforma funziona su un'architettura basata su webhook. Il tuo server riceve messaggi in arrivo tramite webhook, li elabora e risponde utilizzando l'API Send. Questo modello asincrono ti consente di creare esperienze reattive senza dover mantenere le connessioni aperte.

Configurare la tua app Meta

Prima di poter utilizzare l'API di Facebook Messenger, è necessario creare e configurare un'App Meta. Questo processo stabilisce l'identità della tua applicazione e concede l'accesso alla Messenger Platform.

Passo 1: Crea un'app Meta

Naviga verso il Meta per Sviluppatori Accedi al portale e crea una nuova app. Seleziona "Business" come tipo di app, che ti darà accesso alle funzionalità di Messenger.

```typescript
// Variabili d'ambiente necessarie dopo la configurazione
interface MessengerConfig {
  FACEBOOK_APP_ID: string;
  FACEBOOK_APP_SECRET: string;
  FACEBOOK_PAGE_ID: string;
  FACEBOOK_PAGE_ACCESS_TOKEN: string;
  MESSENGER_VERIFY_TOKEN: string;
}

// Valida la tua configurazione all'avvio
function validateConfig(): MessengerConfig {
  const required = [
    'FACEBOOK_APP_ID',
    'FACEBOOK_APP_SECRET', 
    'FACEBOOK_PAGE_ID',
    'FACEBOOK_PAGE_ACCESS_TOKEN',
    'MESSENGER_VERIFY_TOKEN'
  ];
  
  const missing = required.filter(key => !process.env[key]);
  
  if (missing.length > 0) {
    throw new Error(`Variabili d'ambiente richieste mancanti: ${missing.join(', ')}`);
  }
  
  return {
    FACEBOOK_APP_ID: process.env.FACEBOOK_APP_ID!,
    FACEBOOK_APP_SECRET: process.env.FACEBOOK_APP_SECRET!,
    FACEBOOK_PAGE_ID: process.env.FACEBOOK_PAGE_ID!,
    FACEBOOK_PAGE_ACCESS_TOKEN: process.env.FACEBOOK_PAGE_ACCESS_TOKEN!,
    MESSENGER_VERIFY_TOKEN: process.env.MESSENGER_VERIFY_TOKEN!
  };
}
```

Passo 2: Aggiungi il Prodotto Messenger

Nel pannello della tua app, fai clic su "Aggiungi Prodotto" e seleziona Messenger. Questo attiva le funzionalità della Messenger Platform per la tua app.

Passo 3: Collega una Pagina Facebook

Il tuo bot ha bisogno di una Pagina Facebook per inviare e ricevere messaggi. Nelle impostazioni di Messenger, clicca su "Aggiungi o Rimuovi Pagine" e seleziona la pagina che desideri collegare. Genera un Token di Accesso della Pagina, che utilizzerai per autenticare le richieste API.

Nota: I token di accesso alle pagine possono essere a breve o lungo termine. Per le applicazioni in produzione, scambia il tuo token con una versione a lungo termine che dura circa 60 giorni.

interface TokenExchangeResponse {
  access_token: string;
  token_type: string;
  expires_in?: number;
}

async function exchangeForLongLivedToken(
  shortLivedToken: string,
  appId: string,
  appSecret: string
): Promise {
  const baseUrl = 'https://graph.facebook.com/v18.0';
  
  const params = new URLSearchParams({
    grant_type: 'fb_exchange_token',
    client_id: appId,
    client_secret: appSecret,
    fb_exchange_token: shortLivedToken,
  });

  const response = await fetch(`${baseUrl}/oauth/access_token?${params.toString()}`);
  
  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Scambio token fallito: ${error}`);
  }

  const data = await response.json();
  
  if (!data.access_token) {
    throw new Error('Nessun token di accesso restituito dallo scambio token');
  }

  const expiresInDays = data.expires_in 
    ? Math.floor(data.expires_in / 86400) 
    : 'sconosciuto';
    
  console.log(`Token scambiato con successo (scade tra ${expiresInDays} giorni)`);

  return {
    access_token: data.access_token,
    token_type: data.token_type || 'bearer',
    expires_in: data.expires_in,
  };
}

Passo 4: Configura le autorizzazioni dell'app

Richiedi i permessi necessari per il tuo bot. Al minimo, avrai bisogno di:

  • messaggistica_pagineInvia e ricevi messaggi
  • pages_manage_metadataIscriviti ai webhook
  • interazioni_lettura_pagineAccedi ai dati delle conversazioni

Configurazione e Verifica del Webhook

I webhook sono il cuore dell'API della piattaforma messenger. Consentono a Facebook di notificare il tuo server quando si verificano eventi, come messaggi in arrivo o consegne di messaggi.

Impostazione del tuo endpoint Webhook

Crea un endpoint che gestisca sia le richieste GET (per la verifica) sia le richieste POST (per ricevere eventi).

import express, { Request, Response } from 'express';
import crypto from 'crypto';

const app = express();

// Analizza il corpo raw per la verifica della firma
app.use(express.json({
  verify: (req: any, res, buf) => {
    req.rawBody = buf;
  }
}));

// Endpoint di verifica del webhook
app.get('/webhook', (req: Request, res: Response) => {
  const mode = req.query['hub.mode'];
  const token = req.query['hub.verify_token'];
  const challenge = req.query['hub.challenge'];
  
  const verifyToken = process.env.MESSENGER_VERIFY_TOKEN;
  
  if (mode === 'subscribe' && token === verifyToken) {
    console.log('Webhook verificato con successo');
    res.status(200).send(challenge);
  } else {
    console.error('Verifica del webhook fallita');
    res.sendStatus(403);
  }
});

// Ricezione eventi del webhook
app.post('/webhook', (req: Request, res: Response) => {
  // Verifica la firma della richiesta
  const signature = req.headers['x-hub-signature-256'] as string;
  
  if (!verifySignature(req, signature)) {
    console.error('Firma non valida');
    return res.sendStatus(401);
  }
  
  const body = req.body;
  
  if (body.object !== 'page') {
    return res.sendStatus(404);
  }
  
  // Elabora ogni voce
  body.entry?.forEach((entry: any) => {
    entry.messaging?.forEach((event: any) => {
      handleMessagingEvent(event);
    });
  });
  
  // Rispondi sempre rapidamente con 200 OK
  res.sendStatus(200);
});

function verifySignature(req: any, signature: string): boolean {
  if (!signature) return false;
  
  const appSecret = process.env.FACEBOOK_APP_SECRET!;
  const expectedSignature = 'sha256=' + crypto
    .createHmac('sha256', appSecret)
    .update(req.rawBody)
    .digest('hex');
    
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

async function handleMessagingEvent(event: any): Promise {
  const senderId = event.sender.id;
  
  if (event.message) {
    await handleMessage(senderId, event

Iscrizione agli Eventi Webhook

Dopo aver configurato il tuo endpoint, iscriviti agli eventi che desideri ricevere. Nel Meta App Dashboard, configura il tuo URL del webhook e seleziona i campi di iscrizione pertinenti:

  • messages: Messaggi in arrivo
  • messaging_postbacks: Clic sui pulsanti e selezioni di menu
  • opzioni_messaggistica: Consensi degli utenti
  • consegne_messaggi: Conferme di consegna
  • letture_messaggi: Ricevute di lettura

Ricezione Messaggi

Quando gli utenti inviano messaggi al tuo bot, l'API di chat di Facebook li consegna al tuo webhook. I messaggi possono contenere testo, allegati o entrambi.

interface MessengerMessage {
  mid: string;
  text?: string;
  attachments?: Array<{
    type: 'image' | 'video' | 'audio' | 'file' | 'location' | 'fallback';
    payload: {
      url?: string;
      coordinates?: {
        lat: number;
        long: number;
      };
    };
  }>;
  quick_reply?: {
    payload: string;
  };
  reply_to?: {
    mid: string;
  };
}

async function handleMessage(
  senderId: string, 
  message: MessengerMessage
): Promise {
  console.log(`Messaggio ricevuto da ${senderId}:`, message);
  
  // Gestisci le risposte rapide
  if (message.quick_reply) {
    await handleQuickReply(senderId, message.quick_reply.payload);
    return;
  }
  
  // Gestisci gli allegati
  if (message.attachments && message.attachments.length > 0) {
    for (const attachment of message.attachments) {
      await handleAttachment(senderId, attachment);
    }
    return;
  }
  
  // Gestisci i messaggi di testo
  if (message.text) {
    await processTextMessage(senderId, message.text);
  }
}

async function handleAttachment(
  senderId: string, 
  attachment: MessengerMessage['attachments'][0]
): Promise {
  switch (attachment.type) {
    case 'image':
      await sendTextMessage(senderId, `Grazie per l'immagine! Ho ricevuto: ${attachment.payload.url}`);
      break;
    case 'location':
      const { lat, long } = attachment.payload.coordinates!;
      await sendTextMessage(senderId, `Ho ricevuto la tua posizione: ${lat}, ${long}`);
      break;
    default:
      await sendTextMessage(senderId, `Ho ricevuto il tuo ${attachment.type}`);
  }
}

async function processTextMessage(
  senderId: string, 
  text: string
): Promise {
  const lowerText = text.toLowerCase();
  
  if (lowerText.includes('help')) {
    await sendHelpMessage(senderId);
  } else if (lowerText.includes('products')) {
    await sendProductCatalog(senderId);
  } else {
    await sendTextMessage(senderId, `Hai detto: "${text}". Come posso aiutarti oggi?`);
  }
}

Invio di Messaggi di Testo

L'API Send è il tuo strumento principale per rispondere agli utenti tramite l'API del bot di messaggistica. I messaggi di testo sono la forma più semplice di risposta.

const GRAPH_API_URL = 'https://graph.facebook.com/v18.0';

interface SendMessageResponse {
  recipient_id: string;
  message_id: string;
}

interface SendMessageError {
  message: string;
  type: string;
  code: number;
  error_subcode?: number;
  fbtrace_id: string;
}

async function sendTextMessage(
  recipientId: string, 
  text: string
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        message: { text },
        messaging_type: 'RESPONSE'
      }),
    }
  );
  
  const data = await response.json();
  
  if (!response.ok) {
    const error = data.error as SendMessageError;
    throw new Error(`Invio non riuscito: ${error.message} (codice: ${error.code})`);
  }
  
  return data as SendMessageResponse;
}

// Invia un indicatore di digitazione per migliorare l'esperienza utente
async function sendTypingIndicator(
  recipientId: string, 
  isTyping: boolean
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  await fetch(
    `${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        sender_action: isTyping ? 'typing_on' : 'typing_off'
      }),
    }
  );
}

// Funzione di supporto per inviare messaggi con indicatore di digitazione
async function sendMessageWithTyping(
  recipientId: string,
  text: string,
  typingDuration: number = 1000
): Promise {
  await sendTypingIndicator(recipientId, true);
  await new Promise(resolve => setTimeout(resolve, typingDuration));
  return sendTextMessage(recipientId, text);
}

Modelli di Messaggio (Generico, Pulsante, Ricevuta)

I modelli di messaggio creano esperienze ricche e interattive che vanno oltre il semplice testo. L'API di Facebook Messenger supporta diversi tipi di modelli, ognuno progettato per casi d'uso specifici.

Modello Generico

Il Modello Generico mostra un carosello di elementi, ideale per elenchi di prodotti o feed di contenuti.

interface GenericTemplateElement {
  title: string;
  subtitle?: string;
  image_url?: string;
  default_action?: {
    type: 'web_url';
    url: string;
    webview_height_ratio?: 'compact' | 'tall' | 'full';
  };
  buttons?: Array;
}

type TemplateButton = 
  | { type: 'web_url'; url: string; title: string }
  | { type: 'postback'; title: string; payload: string }
  | { type: 'phone_number'; title: string; payload: string }
  | { type: 'account_link'; url: string }
  | { type: 'account_unlink' };

async function sendGenericTemplate(
  recipientId: string,
  elements: GenericTemplateElement[]
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  // Limita a 10 elementi per carosello
  const limitedElements = elements.slice(0, 10);
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        message: {
          attachment: {
            type: 'template',
            payload: {
              template_type: 'generic',
              elements: limitedElements
            }
          }
        },
        messaging_type: 'RESPONSE'
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Invio del template fallito: ${error.error?.message}`);
  }
  
  return response.json();
}

// Esempio: Catalogo prodotti
async function sendProductCatalog(recipientId: string): Promise {
  const products: GenericTemplateElement[] = [
    {
      title: 'Cuffie Wireless',
      subtitle: '149,99 € - Qualità audio premium',
      image_url: 'https://example.com/headphones.jpg',
      default_action: {
        type: 'web_url',
        url: 'https://example.com/products/headphones'
      },
      buttons: [
        { type: 'postback', title: 'Acquista Ora', payload: 'BUY_HEADPHONES' },
        { type:

Modello di Pulsante

Il Modello di Pulsante presenta un messaggio di testo con un massimo di tre pulsanti, ideale per scelte semplici.

async function sendButtonTemplate(
  recipientId: string,
  text: string,
  buttons: TemplateButton[]
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  // Limita a 3 pulsanti
  const limitedButtons = buttons.slice(0, 3);
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        message: {
          attachment: {
            type: 'template',
            payload: {
              template_type: 'button',
              text,
              buttons: limitedButtons
            }
          }
        },
        messaging_type: 'RESPONSE'
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Invio del template pulsante fallito: ${error.error?.message}`);
  }
  
  return response.json();
}

// Esempio: Menu di aiuto
async function sendHelpMessage(recipientId: string): Promise {
  await sendButtonTemplate(
    recipientId,
    'Come posso aiutarti oggi?',
    [
      { type: 'postback', title: 'Sfoglia Prodotti', payload: 'BROWSE_PRODUCTS' },
      { type: 'postback', title: 'Traccia Ordine', payload: 'TRACK_ORDER' },
      { type: 'postback', title: 'Contatta Supporto', payload: 'CONTACT_SUPPORT' }
    ]
  );
}

Modello di Ricevuta

Il Modello di Ricevuta mostra le conferme d'ordine con dettagli specifici.

interface ReceiptElement {
  title: string;
  subtitle?: string;
  quantity?: number;
  price: number;
  currency?: string;
  image_url?: string;
}

interface ReceiptSummary {
  subtotal?: number;
  shipping_cost?: number;
  total_tax?: number;
  total_cost: number;
}

interface ReceiptAddress {
  street_1: string;
  street_2?: string;
  city: string;
  postal_code: string;
  state: string;
  country: string;
}

async function sendReceiptTemplate(
  recipientId: string,
  receipt: {
    recipientName: string;
    orderNumber: string;
    currency: string;
    paymentMethod: string;
    orderUrl?: string;
    timestamp?: string;
    address?: ReceiptAddress;
    elements: ReceiptElement[];
    summary: ReceiptSummary;
  }
): Promise<SendMessageResponse> {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        message: {
          attachment: {
            type: 'template',
            payload: {
              template_type: 'receipt',
              recipient_name: receipt.recipientName,
              order_number: receipt.orderNumber,
              currency: receipt.currency,
              payment_method: receipt.paymentMethod,
              order_url: receipt.orderUrl,
              timestamp: receipt.timestamp,
              address: receipt.address,
              elements: receipt.elements,
              summary: receipt.summary
            }
          }
        },
        messaging_type: 'RESPONSE'
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Il template della ricevuta è fallito: ${error.error?.message}`);
  }
  
  return response.json();
}

// Esempio: Conferma dell'ordine
async function sendOrderConfirmation(
  recipientId: string,
  orderId: string
): Promise<void> {
  await sendReceiptTemplate(recipientId, {
    recipientName: 'Giovanni Rossi

Build faster with Late

One API call to post everywhere. No OAuth headaches. No platform-specific code.

Free tier • No credit card • 99.97% uptime

Risposte Veloci e Menu Persistente

Le Risposte Veloci e il Menu Persistente guidano gli utenti attraverso le conversazioni, offrendo opzioni chiare.

Risposte Veloci

Le Risposte Veloci appaiono come pulsanti sopra la tastiera, offrendo risposte suggerite che scompaiono dopo la selezione.

interface QuickReply {
  content_type: 'text' | 'user_phone_number' | 'user_email';
  title?: string;
  payload?: string;
  image_url?: string;
}

async function sendQuickReplies(
  recipientId: string,
  text: string,
  quickReplies: QuickReply[]
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  // Limita a 13 risposte rapide
  const limitedReplies = quickReplies.slice(0, 13);
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        message: {
          text,
          quick_replies: limitedReplies
        },
        messaging_type: 'RESPONSE'
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Invio delle risposte rapide fallito: ${error.error?.message}`);
  }
  
  return response.json();
}

// Esempio: sondaggio di soddisfazione
async function sendSatisfactionSurvey(recipientId: string): Promise {
  await sendQuickReplies(
    recipientId,
    'Come valuteresti la tua esperienza oggi?',
    [
      { content_type: 'text', title: '😄 Ottima', payload: 'RATING_5' },
      { content_type: 'text', title: '🙂 Buona', payload: 'RATING_4' },
      { content_type: 'text', title: '😐 Così così', payload: 'RATING_3' },
      { content_type: 'text', title: '😕 Scarsa', payload: 'RATING_2' },
      { content_type: 'text', title: '😞 Brutta', payload: 'RATING_1' }
    ]
  );
}

async function handleQuickReply(
  senderId: string, 
  payload: string
): Promise {
  if (payload.startsWith('RATING_')) {
    const rating = parseInt(payload.split('_')[1]);
    await sendTextMessage(
      senderId, 
      `Grazie per il tuo feedback! Ci hai valut

Menu Persistente

Il Menu Persistente offre una navigazione sempre disponibile tramite l'icona dell'hamburger.

interface MenuItem {
  type: 'postback' | 'web_url' | 'nested';
  title: string;
  payload?: string;
  url?: string;
  webview_height_ratio?: 'compact' | 'tall' | 'full';
  call_to_actions?: MenuItem[];
}

async function setPersistentMenu(
  menuItems: MenuItem[],
  locale: string = 'default'
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/messenger_profile?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        persistent_menu: [
          {
            locale,
            composer_input_disabled: false,
            call_to_actions: menuItems
          }
        ]
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Configurazione del menu persistente fallita: ${error.error?.message}`);
  }
  
  console.log('Menu persistente configurato con successo');
}

// Esempio: menu bot e-commerce
async function setupBotMenu(): Promise {
  await setPersistentMenu([
    {
      type: 'postback',
      title: '🛍️ Acquista Ora',
      payload: 'SHOP_NOW'
    },
    {
      type: 'nested',
      title: '📦 I Miei Ordini',
      call_to_actions: [
        { type: 'postback', title: 'Traccia Ordine', payload: 'TRACK_ORDER' },
        { type: 'postback', title: 'Storico Ordini', payload: 'ORDER_HISTORY' },
        { type: 'postback', title: 'Resi', payload: 'RETURNS' }
      ]
    },
    {
      type: 'postback',
      title: '💬 Contatta il Supporto',
      payload: 'CONTACT_SUPPORT'
    }
  ]);
}

Messaggi multimediali (Immagini, Video, File)

L'API della piattaforma di messaggistica supporta allegati multimediali, consentendoti di inviare immagini, video, file audio e documenti.

type AttachmentType = 'immagine' | 'video' | 'audio' | 'file';

interface AttachmentPayload {
  url?: string;
  is_reusable?: boolean;
  attachment_id?: string;
}

async function sendMediaAttachment(
  recipientId: string,
  type: AttachmentType,
  payload: AttachmentPayload
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        message: {
          attachment: {
            type,
            payload
          }
        },
        messaging_type: 'RESPONSE'
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Invio media fallito: ${error.error?.message}`);
  }
  
  return response.json();
}

// Invia immagine tramite URL
async function sendImage(
  recipientId: string, 
  imageUrl: string,
  reusable: boolean = true
): Promise {
  return sendMediaAttachment(recipientId, 'immagine', {
    url: imageUrl,
    is_reusable: reusable
  });
}

// Invia video tramite URL
async function sendVideo(
  recipientId: string, 
  videoUrl: string
): Promise {
  return sendMediaAttachment(recipientId, 'video', {
    url: videoUrl,
    is_reusable: true
  });
}

// Invia file/documento
async function sendFile(
  recipientId: string, 
  fileUrl: string
): Promise {
  return sendMediaAttachment(recipientId, 'file', {
    url: fileUrl,
    is_reusable: true
  });
}

// Carica allegato per riutilizzo
async function uploadAttachment(
  type: AttachmentType,
  url: string
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/message_attachments?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers:

Nota: I file multimediali devono essere accessibili tramite HTTPS. Facebook scarica il file dal tuo URL, quindi assicurati che il tuo server possa gestire il traffico. Per i media utilizzati frequentemente, carica una sola volta e riutilizza l'ID dell'allegato.

Protocollo di Passaggio Umano

Il Protocollo di Passaggio consente transizioni fluide tra bot automatici e agenti umani. Questo è fondamentale per scenari di supporto complessi che richiedono l'intervento umano.

type ThreadOwner = 'primary' | 'secondary';

interface HandoverMetadata {
  reason?: string;
  conversationHistory?: string;
  customData?: Record;
}

// Pass thread control to another app (e.g., human agent inbox)
async function passThreadControl(
  recipientId: string,
  targetAppId: string,
  metadata?: HandoverMetadata
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/pass_thread_control?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        target_app_id: targetAppId,
        metadata: metadata ? JSON.stringify(metadata) : undefined
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Passaggio del controllo del thread non riuscito: ${error.error?.message}`);
  }
  
  console.log(`Controllo del thread passato all'app ${targetAppId}`);
}

// Take thread control back from secondary receiver
async function takeThreadControl(
  recipientId: string,
  metadata?: HandoverMetadata
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/take_thread_control?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        metadata: metadata ? JSON.stringify(metadata) : undefined
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Ripristino del controllo del thread non riuscito: ${error.error?.message}`);
  }
  
  console.log('Controllo del thread ripreso');
}

// Request thread control from primary receiver
async function requestThreadControl(
  recipientId: string,
  metadata?: HandoverMetadata
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/request_thread_control?access

Tag per i messaggi di follow-up

Al di fuori della finestra di messaggistica di 24 ore, è necessario utilizzare i Tag Messaggio per inviare messaggi di follow-up. Questi tag indicano lo scopo del tuo messaggio e devono essere utilizzati in modo appropriato.

type MessageTag = 
  | 'CONFIRMED_EVENT_UPDATE'
  | 'POST_PURCHASE_UPDATE'
  | 'ACCOUNT_UPDATE'
  | 'HUMAN_AGENT';;

async function sendTaggedMessage(
  recipientId: string,
  text: string,
  tag: MessageTag
): Promise {
  const pageAccessToken = process.env.FACEBOOK_PAGE_ACCESS_TOKEN!;
  
  const response = await fetch(
    `${GRAPH_API_URL}/me/messages?access_token=${pageAccessToken}`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        recipient: { id: recipientId },
        message: { text },
        messaging_type: 'MESSAGE_TAG',
        tag
      }),
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Invio messaggio con tag fallito: ${error.error?.message}`);
  }
  
  return response.json();
}

// Esempio: Aggiornamento sulla spedizione dell'ordine
async function sendShippingUpdate(
  recipientId: string,
  orderId: string,
  trackingNumber: string
): Promise {
  await sendTaggedMessage(
    recipientId,
    `Ottime notizie! Il tuo ordine #${orderId} è stato spedito. Traccialo qui: https://example.com/track/${trackingNumber}`,
    'POST_PURCHASE_UPDATE'
  );
}

// Esempio: Avviso di sicurezza dell'account
async function sendSecurityAlert(
  recipientId: string,
  alertType: string
): Promise {
  await sendTaggedMessage(
    recipientId,
    `Avviso di Sicurezza: ${alertType}. Se non sei stato tu, ti preghiamo di mettere in sicurezza il tuo account immediatamente.`,
    'ACCOUNT_UPDATE'
  );
}

// Esempio: Follow-up da un agente umano (entro 7 giorni dal messaggio dell'utente)
async function sendHumanAgentFollowup(
  recipientId: string,
  message: string
): Promise {
  await sendTaggedMessage(
    recipientId,
    message,
    'HUMAN_AGENT'
  );
}

Nota: I tag dei messaggi hanno politiche di utilizzo rigorose. Un uso improprio può comportare la restrizione o il divieto del tuo bot. Il tag HUMAN_AGENT è disponibile solo entro 7 giorni dall'ultimo messaggio dell'utente e richiede un coinvolgimento umano nella risposta.

Limiti di utilizzo e migliori pratiche

L'API di Facebook Messenger impone limiti di frequenza per garantire la stabilità della piattaforma. Comprendere questi limiti ti aiuta a creare bot affidabili.

Panoramica dei Limiti di Richiesta

Tipo di LimiteThresholdWindow
Chiamate per pagina200 chiamatePer ora per utente
Richieste in batch50 richiestePer lotto
Invia API250 messaggiPer secondo per pagina

Gestione dei Limiti di Richiesta

interfaccia StatoLimiteRichieste {
  conteggioRichieste: numero;
  inizioFinestra: numero;
  èLimitato: booleano;
}

classe LimitatoreRichieste {
  private stato: Mappa<string, StatoLimiteRichieste> = new Mappa();
  private readonly maxRichieste: numero;
  private readonly finestraMs: numero;
  
  costruttore(maxRichieste: numero = 200, finestraMs: numero = 3600000) {
    this.maxRichieste = maxRichieste;
    this.finestraMs = finestraMs;
  }
  
  async controllaLimite(pageId: string): Promise<boolean> {
    const adesso = Date.now();
    let stato = this.stato.get(pageId);
    
    if (!stato || adesso - stato.inizioFinestra > this.finestraMs) {
      stato = { conteggioRichieste: 0, inizioFinestra: adesso, èLimitato: false };
    }
    
    if (stato.conteggioRichieste >= this.maxRichieste) {
      stato.èLimitato = true;
      this.stato.set(pageId, stato);
      return false;
    }
    
    stato.conteggioRichieste++;
    this.stato.set(pageId, stato);
    return true;
  }
  
  ottieniTempoReset(pageId: string): numero {
    const stato = this.stato.get(pageId);
    if (!stato) return 0;
    return Math.max(0, this.finestraMs - (Date.now() - stato.inizioFinestra));
  }
}

const limitatoreRichieste = new LimitatoreRichieste();

async function inviaConLimitazioneRichieste(
  pageId: string,
  recipientId: string,
  testo: string
): Promise<RispostaInvioMessaggio | null> {
  const puòProcedere = await limitatoreRichieste.controllaLimite(pageId);
  
  if (!puòProcedere) {
    const tempoReset = limitatoreRichieste.ottieniTempoReset(pageId);
    console.warn(`Limitato. Reset in ${Math.ceil(tempoReset / 1000)}s`);
    return

Migliori Pratiche

  1. Rispondi rapidamenteRiconosci i messaggi entro 20 secondi per evitare errori di timeout.
  2. Utilizza indicatori di digitazioneMostra agli utenti che il tuo bot sta elaborando la loro richiesta.
  3. Gestisci gli errori in modo eleganteFornisci messaggi di errore utili quando qualcosa va storto.
  4. Rispetta le preferenze degli utentiRispetta le richieste di disiscrizione e le azioni di annullamento dell'iscrizione.
  5. Memorizza gli ID degli allegatiCarica i media una sola volta e riutilizza l'ID dell'allegato.
  6. Operazioni in batchRaggruppa più richieste quando possibile.
  7. Implementa la logica di ripetizioneGestisci i guasti temporanei con un backoff esponenziale.
async function sendWithRetry(
  recipientId: string,
  text: string,
  maxRetries: number = 3
): Promise<SendMessageResponse> {
  let lastError: Error | null = null;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await sendTextMessage(recipientId, text);
    } catch (error) {
      lastError = error as Error;
      
      // Controlla se l'errore è ripetibile
      const errorMessage = lastError.message.toLowerCase();
      const isRetryable = 
        errorMessage.includes('timeout') ||
        errorMessage.includes('temporaneamente non disponibile') ||
        errorMessage.includes('limite di frequenza');
      
      if (!isRetryable || attempt === maxRetries) {
        throw lastError;
      }
      
      // Backoff esponenziale
      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Tentativo di ripetizione ${attempt}/${maxRetries} tra ${delay}ms`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  
  throw lastError;
}

Utilizzare Late per l'integrazione con Messenger

Creare e mantenere un'integrazione con Messenger richiede la gestione dei webhook, la gestione dei token, l'elaborazione di vari tipi di messaggi e il monitoraggio delle modifiche all'API. Late semplifica l'intero processo con un'API unificata che funziona su più piattaforme di messaggistica.

Perché scegliere Late per Messenger?

Invece di creare gestori webhook personalizzati, gestire i token e formattare i messaggi per ogni piattaforma, Late offre:

  • API unificataUn'unica interfaccia per inviare messaggi a Messenger, WhatsApp, Instagram e altro ancora.
  • Aggiornamento automatico del tokenToken a lungo termine gestiti automaticamente
  • Aggregazione dei webhookUn endpoint webhook per tutte le piattaforme
  • Astrazione dei modelliScrivi una volta, visualizza correttamente su ogni piattaforma.
  • Limitazione della velocità integrataGestione automatica dei limiti delle piattaforme
  • Normalizzazione degli erroriRisposte di errore coerenti su tutte le piattaforme

Inizia rapidamente con Late

```javascript
import { LateClient } from '@anthropic/late-sdk';

const late = new LateClient({
  apiKey: process.env.LATE_API_KEY!
});

// Invia un messaggio a Messenger (o a qualsiasi piattaforma)
async function sendMessage(
  channelId: string,
  recipientId: string,
  content: string
): Promise {
  await late.messages.send({
    channel: channelId,
    recipient: recipientId,
    content: {
      type: 'text',
      text: content
    }
  });
}

// Invia un template che funziona su tutte le piattaforme
async function sendProductCard(
  channelId: string,
  recipientId: string,
  product: { name: string; price: number; imageUrl: string }
): Promise {
  await late.messages.send({
    channel: channelId,
    recipient: recipientId,
    content: {
      type: 'card',
      title: product.name,
      subtitle: `€${product.price.toFixed(2)}`,
      imageUrl: product.imageUrl,
      buttons: [
        { type: 'postback', title: 'Acquista ora', payload: 'BUY' },
        { type: 'url', title: 'Dettagli', url: 'https://example.com' }
      ]
    }
  });
}
```

Late gestisce automaticamente il formato specifico per ogni piattaforma. Lo stesso codice funziona per Messenger, Instagram Direct, WhatsApp Business e altre piattaforme supportate.

Gestire i Messaggi in Arrivo

Late aggrega i webhook da tutte le piattaforme collegate in un unico endpoint:

// Gestore webhook unico per tutte le piattaforme
app.post('/late-webhook', async (req, res) => {
  const event = req.body;
  
  // Gestione dei messaggi indipendente dalla piattaforma
  if (event.type === 'message') {
    const { platform, channelId, senderId, content } = event;
    
    console.log(`Messaggio da ${platform}: ${content.text}`);
    
    // Rispondi utilizzando l'API unificata di Late
    await late.messages.send({
      channel: channelId,
      recipient: senderId,
      content: {
        type: 'text',
        text: `Grazie per il tuo messaggio!`
      }
    });
  }
  
  res.sendStatus(200);
});

Iniziare

  1. Iscriviti su getlate.dev
  2. Collega la tua Pagina Facebook nel pannello di controllo.
  3. Utilizza l'API unificata di Late per inviare e ricevere messaggi.

La documentazione di Late include guide dettagliate per Integrazione con Messenger, configurazione del webhook, e modelli di messaggio.

Creare esperienze conversazionali non dovrebbe richiedere la gestione di codici separati per ogni piattaforma. Con Late, scrivi la logica del tuo bot una sola volta e raggiungi gli utenti ovunque preferiscano comunicare.

Una API. 13+ piattaforme.

Integra i social in minuti, non settimane.

Progettato per sviluppatori. Apprezzato dalle agenzie. Fidato da 6.325 utenti.