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:
| Feature | Description | Caso d'uso |
|---|---|---|
| Messaggi di testo | Invio e ricezione di messaggi di base | Richieste dei clienti, notifiche |
| Modelli di Messaggio | Layout strutturati con immagini e pulsanti | Cataloghi prodotti, ricevute |
| Risposte Veloci | Pulsanti di risposta suggeriti | Conversazioni guidate, sondaggi |
| Menu Persistente | Opzioni di navigazione sempre disponibili | Navigazione del bot, azioni comuni |
| Messaggi Multimediali | Immagini, video, audio e file | Immagini del prodotto, tutorial |
| Protocollo di Passaggio | Trasferimento tra bot e agenti umani | Escalazione 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 messaggipages_manage_metadataIscriviti ai webhookinterazioni_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 arrivomessaging_postbacks: Clic sui pulsanti e selezioni di menuopzioni_messaggistica: Consensi degli utenticonsegne_messaggi: Conferme di consegnaletture_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
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 Limite | Threshold | Window |
|---|---|---|
| Chiamate per pagina | 200 chiamate | Per ora per utente |
| Richieste in batch | 50 richieste | Per lotto |
| Invia API | 250 messaggi | Per 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
- Rispondi rapidamenteRiconosci i messaggi entro 20 secondi per evitare errori di timeout.
- Utilizza indicatori di digitazioneMostra agli utenti che il tuo bot sta elaborando la loro richiesta.
- Gestisci gli errori in modo eleganteFornisci messaggi di errore utili quando qualcosa va storto.
- Rispetta le preferenze degli utentiRispetta le richieste di disiscrizione e le azioni di annullamento dell'iscrizione.
- Memorizza gli ID degli allegatiCarica i media una sola volta e riutilizza l'ID dell'allegato.
- Operazioni in batchRaggruppa più richieste quando possibile.
- 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
- Iscriviti su getlate.dev
- Collega la tua Pagina Facebook nel pannello di controllo.
- 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.