Il recupero dei servizi Zoho tramite il livello API richiede una connessione OAuth valida, un access token attivo e il tipo di app corretto — se uno di questi elementi non è configurato correttamente, ogni chiamata successiva restituirà silenziosamente None.
Perché è importante
Quando si creano automazioni o integrazioni su Zoho CRM o Zoho Desk, ogni chiamata agli strumenti deve prima risolvere un'istanza API funzionante per l'utente autenticato. Se la ricerca della connessione fallisce, o il token è scaduto senza essere stato aggiornato, non verrà restituito alcun dato di servizio. Comprendere l'intera catena di recupero — dalla ricerca nel database all'aggiornamento del token fino all'istanziazione dell'API — consente di diagnosticare i problemi rapidamente e di creare integrazioni più resilienti. In qualità di supporto esperto indipendente per Zoho (non supporto ufficiale Zoho), Beam Help documenta questo flusso affinché il tuo team possa gestirlo con sicurezza.
Procedura passo dopo passo
Passaggio 1. Verifica che le variabili d'ambiente siano configurate prima di tentare qualsiasi connessione. Come minimo, è necessario che ZOHOCLIENTID, ZOHOCLIENTSECRET e OPENROUTERAPIKEY siano definiti in un file .env nella directory radice del progetto. Puoi anche impostare ZOHO_DC per puntare a un data center specifico (ad esempio eu, in, com.au o jp; il valore predefinito è com). [8]
Passaggio 2. Assicurati che il server sia in esecuzione prima di qualsiasi tentativo di recupero. Avvialo con:
python3 server.py
Puoi verificare che sia in ascolto eseguendo lsof -i :8080. [8]
Passaggio 3. Recupera la connessione Zoho memorizzata per un determinato utente chiamando getzohoconnection(userid). Questa funzione interroga la tabella zohoconnections cercando il user_id corrispondente. Se non viene trovata alcuna riga, la funzione restituisce None e nessun ulteriore recupero è possibile. [3]
Passaggio 4. La funzione di connessione gestisce automaticamente la scadenza del token. Confronta l'ora corrente con tokenexpiresat, applicando un buffer di aggiornamento anticipato di 120 secondi per ridurre gli errori 401 a metà richiesta. Quando è necessario un aggiornamento, chiama ZohoOAuth.refreshtokens() con il refreshtoken memorizzato, quindi scrive il nuovo accesstoken e il tokenexpires_at aggiornato nel database prima di restituire l'oggetto di connessione aggiornato. [3]
Passaggio 5. Passa la connessione risolta a getzohoapi(userid, apptype), specificando "crm" o "desk" come apptype. Questa funzione chiama getzoho_connection internamente, quindi se la connessione è assente restituisce immediatamente (None, None). [1]
Passaggio 6. Per Zoho Desk in particolare, la funzione richiede anche un orgid. Legge deskorgid dal record di connessione. Se quel campo è vuoto, individua automaticamente l'organizzazione chiamando api.getall_organizations(), quindi estrae l'id del primo elemento dalla lista data restituita e lo salva per le chiamate future. [1]
Passaggio 7. Per Zoho CRM, puoi verificare che la connessione funzioni controllando che il crmorgid memorizzato sia presente nella tabella zohoconnections. Il test harness esegue questa operazione recuperando la riga più recente e passando crmorg_id a una fase di validazione dell'organizzazione sandbox. [5]
Passaggio 8. Una volta ottenuta un'istanza API attiva, le chiamate agli strumenti vengono inviate tramite executetoolwithrepair(), che accetta l'oggetto api, l'apptype, una stringa tool con il nome dello strumento e un dizionario params. Il livello di streaming emette un evento di stato — "Calling Zoho tool: <toolname>..." — prima di ogni esecuzione, così puoi osservare l'avanzamento in tempo reale. [2]
Passaggio 9. Se hai bisogno di recuperare i dettagli dell'utente o dell'organizzazione indipendentemente da una chiamata agli strumenti, usa ZohoOAuth.getuserinfo(accesstoken). Questa funzione accede a https://accounts.zoho.<DC>/oauth/user/info con un header Bearer token e restituisce campi tra cui ZUID (ID utente), Email e identificatori dell'organizzazione. Tieni presente che i nomi dei campi variano in base al data center — la funzione prova orgid, organization_id e ZGID in sequenza prima di ricorrere all'ID utente come fallback. [4]
Errori comuni
orgidmancante per le chiamate a Desk. Sedeskorg_idnon è memorizzato e anche la chiamata di auto-discovery fallisce, il client API di Desk verrà inizializzato con una stringa vuota, causando il fallimento silenzioso di tutte le successive richieste a Desk. Verifica sempre che l'org ID sia salvato dopo la prima connessione riuscita. [1]- Aggiornamento del token che non restituisce
accesstoken. La closuretokenrefresherverifica la presenza della chiave"accesstoken"nella risposta di aggiornamento; se è assente, il refresher restituisceNonee l'istanza API utilizzerà un token non aggiornato. Questo indica in genere che ilrefreshtokenstesso è scaduto e l'utente deve riconnettersi tramite il flusso OAuth. [1] - Mancata corrispondenza del data center. La variabile d'ambiente
ZOHO_DCdeve corrispondere alla regione in cui è stato creato l'account Zoho. Una mancata corrispondenza fa sì che le chiamate OAuth e API raggiungano l'endpoint errato, producendo errori di autenticazione anche con credenziali valide. [4] [8] - Autenticazione degli strumenti browser. Se stai utilizzando strumenti basati su browser (ad es.
browsernavigateandscreenshot), la sessione del browser viene autenticata separatamente dalla sessione API. Una sessione browser scaduta restituisce un erroreactionrequiredche richiede una chiamataPOST /api/browser/loginanziché un normale aggiornamento del token. [6]
Cosa verificare
- Conferma che esista una riga in
zohoconnectionsper iluseriddi destinazione e chetokenexpiresatsia un timestamp Unix futuro valido. [3] - Verifica che
deskorgid(per Desk) ocrmorgid(per CRM) sia popolato nel record di connessione, in modo che l'istanza API si inizializzi con il contesto organizzativo corretto. [1] [5] - Dopo qualsiasi modifica all'ambiente, riavvia il server (
pkill -f "python3 server.py"; sleep 1; python3 server.py) ed esegui nuovamente un controllo della connessione per assicurarti che le nuove variabili siano caricate. [8]