IFIntelFriends — Integrazione API

Guida all'integrazione API
Messaggistica WhatsApp per comunicazioni pre e post appuntamento

Come un gestionale sanitario si integra con il servizio IntelFriends per l'invio automatico di conferme, promemoria, richieste di recensione e richiami. Documento pensato per il team tecnico del gestionale partner.

v0.10 — 15 settembre 2026

1. Concetti generali

L'integrazione avviene tramite una singola API REST. Il gestionale invia una richiesta HTTP ogni volta che un paziente deve ricevere un messaggio WhatsApp; IntelFriends si occupa della consegna effettiva attraverso l'infrastruttura WhatsApp Business.

  • Protocollo: HTTPS esclusivamente. Le richieste in HTTP vengono rifiutate.
  • Formato: JSON, sia in richiesta sia in risposta.
  • Modello: asincrono. La richiesta viene accettata e messa in coda; l'invio effettivo avviene a breve giro, non all'interno della stessa risposta HTTP.
  • Ogni gestionale partner riceve credenziali dedicate, distinte da quelle di altri gestionali.

2. Autenticazione

Ogni richiesta deve includere una API key nell'header HTTP Authorization, in formato Bearer token.

Authorization: Bearer if_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

La API key identifica univocamente il gestionale partner: non è necessario indicare il nome del gestionale nel corpo della richiesta. La chiave viene fornita da IntelFriends al momento dell'attivazione ed è revocabile su richiesta o in caso di necessità.

Una chiave può operare soltanto sui clienti finali del proprio gestionale. Una richiesta che indica un client_ref appartenente a un altro gestionale viene respinta con 403.

Attenzione La API key va trattata come una password: non va condivisa, non va inserita in repository di codice e non va conservata in sistemi non protetti. Per la rotazione IntelFriends emette la nuova chiave prima di revocare la precedente, così da non interrompere il servizio.

3. Identificazione del cliente finale

Ogni richiesta deve indicare a quale cliente finale — cioè a quale studio o clinica — si riferisce il messaggio, tramite il campo client_ref.

  • client_ref è l'identificativo che il gestionale utilizza internamente per quel cliente: non è necessario adottare un nuovo sistema di codici.
  • IntelFriends mantiene la mappatura fra client_ref e la configurazione tecnica necessaria all'invio, che resta interamente a nostro carico.
  • Un client_ref non configurato fa respingere la richiesta con 404: nessun cliente viene creato automaticamente.
  • Un cliente sospeso fa respingere la richiesta con 403.
Prima di andare in produzione Per ogni nuovo cliente finale serve un passaggio di attivazione lato IntelFriends: il client_ref va concordato prima del primo invio.

4. Invio di un messaggio

Endpoint

POST https://api.intelfriends.com/v1/messages

Header

Authorization:   Bearer if_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type:    application/json
Idempotency-Key: 7c1b2e44-9f3a-4d2e-8b1a-2f6e9c0d1a5b

Esempio di richiesta

{
  "client_ref": "STUDIO_ROSSI_MILANO",
  "recipient": "+393331234567",
  "template": "m01_promemoria_richiesta_conferma",
  "variables": {
    "elenco_appuntamenti": "Mario Rossi, 07 Agosto 2026 alle 10:30",
    "indirizzo_completo": "Via Roma 12, Milano",
    "dettagli_aggiuntivi": "Arrivare 10 minuti prima",
    "link_conferma": "https://gestionale.esempio.it/c/8f3k2"
  }
}

Esempio di risposta 202 Accepted

{
  "message_id": "msg_H7y2HKTZLz0PIYWd",
  "status": "queued"
}

Il message_id è il riferimento univoco del messaggio: va conservato per consultarne lo stato (sezione 8) e per qualsiasi segnalazione al supporto.

CampoObbligatorioDescrizione
client_refsìIl cliente finale a cui si riferisce il messaggio.
recipientsìNumero del paziente in formato internazionale E.164, con il + iniziale. Un formato diverso viene respinto con 400 invalid_recipient.
templatesìNome del messaggio, fra quelli elencati alla sezione 6.
variablesdipendeOggetto con le variabili richieste dal messaggio scelto.

5. Variabili disponibili

Le variabili si passano come oggetto nominato, non come elenco posizionale: l'integrazione resta leggibile e non si rompe se in futuro cambia l'ordine dei segnaposti nel testo approvato.

VariabileTipoDescrizioneEsempio
elenco_appuntamentistringa liberaGli appuntamenti da citare nel messaggio, già scritti come devono comparire."Mario Rossi, 07 Agosto 2026 alle 10:30"
indirizzo_completostringaIndirizzo dello studio, mostrato nel messaggio."Via Roma 12, Milano"
dettagli_aggiuntivistringaNota libera aggiunta in coda al corpo del messaggio."Arrivare 10 minuti prima"
link_confermaURL httpsIndirizzo aperto dal bottone Confermo.".../c/8f3k2"
link_recensioneURL httpsIndirizzo aperto dal bottone della recensione.".../recensione"
link_anamnesiURL httpsIndirizzo del modulo di anamnesi da compilare prima della visita.".../anamnesi/8f3k2"
nomestringaNome del paziente, usato nel saluto di apertura. È facoltativa su tutti i messaggi: se non viene fornita, al suo posto compare la parola paziente, quindi il messaggio si apre con "Gentile paziente"."Mario"

Formato di elenco_appuntamenti

È una stringa libera, non un elenco strutturato: viene inserita nel testo del messaggio così com'è. Può descrivere anche più appuntamenti nella stessa stringa, ad esempio "Mario Rossi alle 10:00 e Luigi Verdi alle 11:00". La formattazione della data è quindi a carico del gestionale, che è l'unico a sapere come vanno raggruppati e presentati gli appuntamenti di quel paziente.

Regole di validazione

Ogni variabile il cui nome comincia per link_ deve essere un indirizzo https valido: vale per quelle elencate qui sopra e per qualsiasi altra venga aggiunta in futuro. Un indirizzo http o malformato fa respingere la richiesta con 400.

Le variabili obbligatorie mancanti, vuote o composte di soli spazi fanno respingere la richiesta con 400 missing_variables, con l'elenco di quanto manca.

Le variabili non previste dal messaggio scelto vengono ignorate, non causano errore: è possibile inviare sempre lo stesso insieme di dati cambiando solo il nome del messaggio.

6. Messaggi disponibili

Il campo template deve contenere uno dei nomi elencati qui sotto. L'elenco è concordato fra IntelFriends e il gestionale, ed è lo stesso per tutti i clienti finali di quel gestionale: un nome che non vi compare fa respingere la richiesta con 400 template_not_found, prima che il messaggio entri in coda.

Ogni messaggio richiede solo il sottoinsieme di variabili indicato. I bottoni sono elementi strutturati del template WhatsApp, distinti dal testo del corpo: non vanno inseriti nel messaggio, basta fornire il link a cui puntano.

m01_conferma_appuntamento_prenotatoUtilityConferma di un appuntamento già fissato
Obbligatorieelenco_appuntamenti indirizzo_completo
Facoltativedettagli_aggiuntivi nome
Bottoninessuno
Testo del messaggio

Gentile nome, le confermiamo i dettagli della sua prenotazione:

elenco_appuntamenti

📍 Ci trova in indirizzo_completo

dettagli_aggiuntivi

A presto

m01_promemoria_informativoUtilityPromemoria pre-appuntamento, senza azione richiesta
Obbligatorieelenco_appuntamenti indirizzo_completo
Facoltativedettagli_aggiuntivi nome
Bottoninessuno
Testo del messaggio

Gentile nome, questo è un promemoria per ricordarle i dettagli della sua prenotazione:

elenco_appuntamenti

📍 Ci trova in indirizzo_completo

dettagli_aggiuntivi
A presto

m01_promemoria_richiesta_confermaUtilityPromemoria con richiesta di conferma
Obbligatorieelenco_appuntamenti indirizzo_completo link_conferma
Facoltativedettagli_aggiuntivi nome
Testo del messaggio

Gentile nome,
questo è un promemoria per ricordarle che la attendiamo in studio secondo il seguente programma:

elenco_appuntamenti

📍 Ci trova in indirizzo_completo
La preghiamo di confermare la sua presenza cliccando sul pulsante in basso.

dettagli_aggiuntivi
A presto

✅ Confermo → link_conferma
m01_promemoria_richiesta_anamnesiUtilityPromemoria con richiesta di compilare l'anamnesi
Obbligatorieelenco_appuntamenti indirizzo_completo link_anamnesi
Facoltativedettagli_aggiuntivi nome
Testo del messaggio

Gentile nome,
questo è un promemoria per ricordarle che la attendiamo in studio secondo il seguente programma:

elenco_appuntamenti

📍 Ci trova in indirizzo_completo
La vostra anamnesi risulta scaduta e vi invitiamo alla compilazione prima di arrivare in studio.

dettagli_aggiuntivi
A presto

📝 Compila l'anamnesi → link_anamnesi
m01_richiesta_recensioneMarketingRichiesta di recensione post-trattamento
Obbligatorielink_recensione
Facoltativenome
Testo del messaggio

Gentile nome, rimaniamo a disposizione per qualsiasi domanda sul post trattamento.

La sua recensione su Google aiuterebbe altre persone a trovarci. Grazie!

⭐ Lascia una recensione → link_recensione
m01_promemoria_igieneUtilityPromemoria di un appuntamento di igiene orale
Obbligatorieelenco_appuntamenti link_conferma
Facoltativedettagli_aggiuntivi nome
Testo del messaggio

Gentile nome,
le ricordiamo i dettagli del suo appuntamento d'igiene orale in programma:

elenco_appuntamenti

La preghiamo di confermare la sua presenza cliccando sul pulsante in basso.
dettagli_aggiuntivi

La ringrazio e Le auguro una buona giornata.

✅ Confermo → link_conferma
m01_risposta_alla_confermaUtilityRisposta al paziente dopo la conferma
Obbligatorienessuna
Facoltativenome
Bottoninessuno
Testo del messaggio

Gentile nome,
grazie per aver confermato la sua presenza

m01_sollecito_genericoUtilitySollecito di conferma
Obbligatorienessuna
Facoltativenome
Bottoninessuno
Testo del messaggio

Gentile nome,
Per poterle offrire il miglior servizio, la preghiamo di confermare l'appuntamento.

Non porta bottone: è un semplice sollecito e rimanda alla richiesta di conferma già inviata al paziente, dove il bottone c'è. Va quindi usato dopo m01_promemoria_richiesta_conferma, non al suo posto.

Come cambia l'elenco

L'elenco non è congelato: può essere ampliato con messaggi nuovi e una voce può essere ritirata quando non serve più.

  • Un messaggio nuovo si concorda con IntelFriends definendo nome, variabili obbligatorie e facoltative ed eventuali bottoni. Dal momento dell'attivazione è utilizzabile senza alcun intervento sull'integrazione esistente: basta indicarne il nome nel campo template.
  • Un messaggio ritirato resta leggibile nello storico, ma le nuove richieste che lo utilizzano vengono respinte con 400 template_deprecated. Il ritiro viene comunicato con anticipo.
  • L'elenco vale per tutti i clienti finali del gestionale: non esistono elenchi diversi per singolo studio.

I testi qui riportati sono quelli approvati secondo le regole WhatsApp. Una modifica del testo comporta una nuova approvazione e viene comunicata prima di entrare in vigore.

7. Idempotenza

Per evitare invii duplicati in caso di timeout, retry automatici, errori di rete o doppia esecuzione di una procedura, ogni richiesta può includere un header Idempotency-Key con un valore univoco per il singolo messaggio: si consiglia un UUID v4, generato dal gestionale.

Idempotency-Key: 7c1b2444-4f13-4a90-8b3e-861e2fe5e93e

L'header è facoltativo, ma fortemente consigliato: senza, due richieste identiche generano due messaggi e il paziente li riceve entrambi.

  • Stessa chiave, stesso corpo: viene restituita la risposta originale, con lo stesso message_id, senza generare un secondo messaggio. La risposta riporta l'header Idempotent-Replay: true.
  • Stessa chiave, corpo diverso: la richiesta viene rifiutata con 409. È il segnale che quella chiave è già stata usata per un altro messaggio.
  • Le chiavi sono conservate per 48 ore; oltre tale periodo lo stesso valore può essere riutilizzato.

8. Stato dei messaggi e consuntivi

Stato di un singolo messaggio

GET https://api.intelfriends.com/v1/messages/{message_id}
{
  "message_id": "msg_H7y2HKTZLz0PIYWd",
  "client_ref": "STUDIO_ROSSI_MILANO",
  "template_name": "promemoria_richiesta_conferma",
  "recipient": "+393331234567",
  "status": "delivered",
  "attempts": 1,
  "error_code": null,
  "error_message": null,
  "created_at": "2026-08-09T09:12:31.089Z",
  "sent_at": "2026-08-09T09:12:31.112Z",
  "delivered_at": "2026-08-09T09:12:34.470Z"
}

La consultazione è possibile solo per i messaggi del proprio gestionale: un message_id altrui o inesistente risponde 404.

StatoSignificato
queuedAccettato e in attesa di invio.
sendingInvio in corso.
sentConsegnato all'infrastruttura di messaggistica. sent_at riporta il momento.
deliveredRecapitato al telefono del paziente. delivered_at riporta il momento.
readin arrivoAperto dal paziente.
failedInvio non riuscito. error_code ed error_message riportano il motivo.

Lo stato avanza sempre in avanti e non torna mai indietro: una volta registrata la consegna, un'informazione più vecchia che arriva in ritardo non la cancella.

Quanto aspettare prima di preoccuparsi

Il passaggio da sent a delivered non è immediato: la propagazione della conferma richiede almeno 5 minuti. Un messaggio ancora sent entro quella finestra è del tutto normale e non va segnalato né rimandato.

Prima di ritentare Un messaggio failed ha già esaurito i tentativi automatici previsti. Un nuovo invio è una richiesta nuova, con una Idempotency-Key nuova: ripetere la precedente restituirebbe la risposta originale senza inviare nulla.

Consuntivo

GET https://api.intelfriends.com/v1/usage?client_ref=...&from=2026-08-01&to=2026-09-01
{
  "partner": "gestionale",
  "from": "2026-08-01",
  "to": "2026-09-01",
  "conteggio_su": "accettati",
  "righe": [
    { "client_ref": "STUDIO_ROSSI_MILANO", "template_name": "conferma",
      "status": "sent", "messaggi": 128, "fatturabili": 128 }
  ]
}

Restituisce il conteggio dei messaggi per cliente finale, messaggio e stato nel periodo indicato. I tre parametri sono facoltativi: senza client_ref il conteggio copre tutti i clienti del gestionale, senza date copre l'intero storico. L'intervallo include from ed esclude to.

9. Codici di risposta

CodiceStatoSignificato
202AcceptedRichiesta ricevuta e messa in coda. L'invio effettivo avviene a breve.
400Bad RequestPayload non valido. Il campo error.code distingue il motivo: missing_variables, invalid_recipient, template_not_found, template_deprecated, invalid_payload.
401UnauthorizedAPI key assente, non valida o revocata.
403ForbiddenIl client_ref indicato non appartiene al gestionale associato alla chiave, oppure il cliente è sospeso.
404Not Foundclient_ref non configurato, oppure message_id inesistente.
409ConflictIdempotency-Key già utilizzata con un payload differente.
429Too Many RequestsLimite superato. L'header Retry-After indica dopo quanti secondi riprovare. Il campo error.code distingue i due casi: rate_limited è un limite al minuto, limite_giornaliero_clinica è il tetto di avvio di uno studio appena attivato (sezione 10).
500Internal Server ErrorErrore lato IntelFriends. Sicuro da ritentare con la stessa Idempotency-Key.

In caso di errore il corpo della risposta include un campo error con codice e messaggio leggibile. Il codice è pensato per essere gestito dal programma, il messaggio per essere letto da una persona:

{
  "error": {
    "code": "missing_variables",
    "message": "Variabili obbligatorie mancanti: link_conferma.",
    "missing": ["link_conferma"]
  }
}

I codici 4xx segnalano un problema nella richiesta e non vanno ritentati identici: la richiesta verrebbe respinta allo stesso modo. I 5xx vanno ritentati, riusando la stessa Idempotency-Key.

10. Limiti di frequenza

Le API sono soggette a limiti di frequenza su due livelli, entrambi al minuto: per API key e per singolo client_ref. Il secondo livello garantisce che un singolo studio in condizione anomala non consumi la capacità assegnata a tutti gli altri.

A questi se ne aggiunge un terzo solo per gli studi appena attivati: un tetto sul numero di pazienti diversi contattabili nelle 24 ore. Non è un limite IntelFriends, è la soglia che WhatsApp applica a un numero di telefono appena acceso. Decade da solo a una data stabilita in fase di attivazione e non riguarda gli studi già a regime.

Come si leggono dalla risposta

Ogni risposta riporta lo stato di tutti i limiti che si applicano a quella richiesta: due sull'invio di un messaggio, tre se lo studio è nel periodo di avvio, uno sulle chiamate di sola lettura. Il nome del limite sta nell'header, così si legge direttamente quello che interessa senza doverlo interpretare.

HeaderCosa riporta
X-RateLimit-Gestionale-Limit
X-RateLimit-Gestionale-Remaining
X-RateLimit-Gestionale-Reset
Il limite della vostra API key: quante richieste al minuto, quante ne restano, fra quanti secondi riparte il conteggio. Presente su tutte le chiamate.
X-RateLimit-Clinica-Limit
X-RateLimit-Clinica-Remaining
X-RateLimit-Clinica-Reset
Lo stesso, per il singolo client_ref indicato nella richiesta. Presente sull'invio di un messaggio.
X-RateLimit-Giornaliero-Limit
X-RateLimit-Giornaliero-Remaining
X-RateLimit-Giornaliero-Reset
X-RateLimit-Giornaliero-Fino-Al
Presente solo per gli studi nel periodo di avvio. Remaining sono pazienti diversi ancora contattabili nelle 24 ore, non richieste: un secondo messaggio a chi è già stato contattato oggi passa e non consuma niente. Reset dice fra quanti secondi si libera il primo posto — la finestra è mobile, i posti tornano liberi uno alla volta. Fino-Al è la data in cui il tetto decade.

Oltre a questi, tre header senza nome — X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset — riportano il limite che si esaurirà per primo, cioè quello che fermerà la richiesta successiva, e X-RateLimit-Vincolante dice quale dei tre è. A chi vuole rallentare da solo prima di essere respinto bastano questi quattro.

  • Al superamento la risposta è 429 con header Retry-After in secondi. Gli header dei limiti sono presenti anche sulla risposta respinta.
  • I due 429 vanno distinti dal campo error.code: su rate_limited si riprova entro il minuto, su limite_giornaliero_clinica si riprende dopo ore. In entrambi i casi Retry-After dice quanto aspettare.
  • I valori in vigore vengono comunicati in fase di attivazione. Sono stabiliti per singolo gestionale — entrambi i livelli al minuto — e possono essere modificati su richiesta, con effetto immediato e senza interruzioni.
Invii pianificati in blocco Per gli invii prevedibili in massa, come i promemoria notturni per il giorno successivo, conviene distribuire le richieste nel tempo invece di inviarle tutte nello stesso istante. Il servizio è asincrono: accodare gradualmente non ritarda la consegna ai pazienti. Se sono previste finestre particolarmente concentrate, vanno concordate preventivamente.

11. Sicurezza

  • Tutte le richieste devono avvenire esclusivamente via HTTPS.
  • La API key non va mai inclusa nell'URL o nei parametri in query, ma solo nell'header Authorization.
  • Si raccomanda la rotazione periodica della chiave. IntelFriends emette la nuova chiave prima di revocare la precedente, mantenendo la continuità del servizio.
  • Nel campo dettagli_aggiuntivi non vanno inseriti dati sanitari oltre a quanto strettamente necessario al messaggio: è testo che finisce su WhatsApp, sul telefono del paziente.
  • I dati dei pazienti trasmessi vengono trattati esclusivamente per la finalità dell'invio e conservati per il tempo necessario all'invio e al supporto tecnico.

12. Evoluzioni previste

Le seguenti funzionalità non fanno parte della versione attuale e potranno essere aggiunte in versioni successive:

  • Webhook di notifica verso il gestionale al cambio di stato di un messaggio, in alternativa alla consultazione descritta alla sezione 8.
  • Tracciamento delle interazioni sui bottoni di conferma e modifica.
  • Ricezione dei messaggi inviati dal paziente in risposta.
  • Allegati e contenuti multimediali.

Gli aggiornamenti a questo documento sono numerati in modo incrementale e comunicati al team tecnico del gestionale partner.