Porta un agente OpenAI Agents SDK su WhatsApp
Imposta la destinazione del webhook del numero su una route della tua app Python. Per ogni messaggio in arrivo, esegui l'agente con Runner.run e una sessione legata al numero del mittente, poi rimanda result.final_output tramite la Cloud API con il token del numero e l'ID del numero di telefono. L'app WhatsApp Business continua a funzionare sullo stesso numero.
La sessione integrata dell'SDK, su file o in memoria, che ricorda i turni precedenti sotto un ID di sessione.
MCPServerStreamableHttp accetta qui un httpx.Auth, oppure un header Authorization, per autenticare il server.
La versione della Graph API usata negli esempi attuali di invio messaggi di Meta.
Come diventa un messaggio WhatsApp l'esecuzione di un agente?
Tramite una route della tua applicazione che Meta chiama. Imposta la destinazione del webhook del numero su di essa, con un segreto lungo e casuale nel percorso. La route risponde alla GET di verifica di Meta restituendo hub.challenge come testo semplice, accetta ogni POST, risponde subito 200 e mette il lavoro in coda, perché Meta rinvia la consegna se la risposta è lenta e l'agente verrebbe eseguito due volte.
Un worker legge poi mittente e testo dal payload e chiama Runner.run. Passa una sessione il cui ID è il numero del mittente: l'SDK salva la conversazione con quell'ID, quindi il messaggio successivo dello stesso cliente riprende da dove si era fermato il precedente e due clienti non condividono mai la cronologia. SQLiteSession basta per iniziare; l'SDK include anche sessioni Redis e SQLAlchemy per più worker.
Il segreto nell'URL è l'autenticazione in questo caso. Meta firma le consegne con l'app secret del Tech Provider, quindi l'header della firma non può essere validato dal cliente.
import os, httpx
from agents import Agent, Runner, SQLiteSession
agent = Agent(name="Front desk", instructions="Answer briefly and politely.")
URL = f"https://graph.facebook.com/v25.0/{os.environ['PHONE_NUMBER_ID']}/messages"
async def handle(sender: str, text: str) -> None:
session = SQLiteSession(sender, "whatsapp.db")
result = await Runner.run(agent, text, session=session)
async with httpx.AsyncClient() as http:
await http.post(
URL,
headers={"Authorization": f"Bearer {os.environ['WA_TOKEN']}"},
json={"messaging_product": "whatsapp", "to": sender,
"type": "text", "text": {"body": result.final_output}},
)Perché a inviare la risposta dovrebbe essere il tuo codice e non l'agente?
Perché l'unica regola da non violare è una regola di tempo, e il codice la fa rispettare meglio di un prompt. Meta apre una finestra di assistenza clienti di 24 ore quando un cliente scrive. Al suo interno passa il testo libero. Fuori, passa solo un template approvato, e il testo libero torna indietro con l'errore 131047.
Un worker che risponde al messaggio appena arrivato è sempre dentro la finestra, quindi inviare result.final_output come testo è sicuro per costruzione. Il lavoro che avviene dopo, un follow up il mattino seguente o un promemoria, dovrebbe passare da un percorso separato che invia un template e mai testo libero.
L'agente può comunque avere strumenti. Dagli function tool per cercare informazioni, come un ordine o una prenotazione, e lascia l'invio su WhatsApp nel worker. Così il token di accesso resta fuori da qualsiasi cosa il modello possa chiamare con argomenti arbitrari.
L'agente può usare il server MCP di EasyCoexistence?
Può, tramite MCPServerStreamableHttp, con una configurazione più lunga di un semplice header. L'SDK accetta un header Authorization oppure un httpx.Auth in params["auth"]. Il server MCP di EasyCoexistence emette i propri token OAuth dopo un accesso dal browser, con registrazione dinamica del client e PKCE, quindi non esiste una chiave statica. L'SDK Python di MCP include OAuthClientProvider, un gestore di autenticazione HTTP che esegue quel flusso con PKCE e rinnovo del token, ed è ciò che va in params["auth"].
Vale la pena quando l'agente deve decidere da solo: controllare lo stato di salute di un numero, leggere lo stato dei template o scegliere tra send_message e send_template in base alle regole nelle descrizioni degli strumenti. Per un front desk che si limita a rispondere, il worker descritto sopra è più corto e ha meno punti in cui rompersi.
In ogni caso il webhook resta. MCP funziona a richiesta e risposta, e il messaggio di un cliente può raggiungere l'agente solo attraverso la route che Meta chiama.
Errori comuni
- Eseguire l'agente prima di rispondere 200 a Meta. Una risposta lenta viene ritentata e il cliente riceve due risposte.
- Usare una sola sessione per tutti i clienti. Legala al numero del mittente, altrimenti le cronologie si mescolano.
- Lasciare che un follow up in ritardo invii testo libero. Dopo 24 ore fallisce con l'errore 131047; invia invece un template.
Collega il numero su easycoexistence.com, imposta la destinazione del webhook sulla tua route e leggi il token e l'ID del numero di telefono dalla dashboard. Da US$ 9 per numero al mese, fino a US$ 1 man mano che aggiungi numeri, con i primi 3 giorni di prova gratuita.
Domande frequenti
Serve il tool MCP ospitato dell'API OpenAI Responses?
No. Il worker esegue l'agente in locale con Runner.run, e il lato WhatsApp è una normale chiamata HTTPS fatta dal tuo codice.
Quale versione della Graph API devo usare?
Gli esempi attuali di Meta usano v25.0. Fissa una versione in un solo punto del codice, così l'aggiornamento è una modifica di una riga.
Una persona può subentrare dal telefono?
Sì. Coexistence mantiene attiva l'app WhatsApp Business, e una risposta dal telefono arriva alla tua route come evento echo che il worker può usare per mettere in pausa l'agente.
EasyCoexistence salva la conversazione?
No. Meta consegna direttamente alla tua route. Ciò che la sessione memorizza resta nel tuo database.
Continua a leggere
Pronto per iniziare?
Configura WhatsApp Coexistence in pochi minuti, non in mesi. L'app continua a funzionare sul telefono.
Inizia la prova gratuitaVerificato il