Passa al contenuto principale

UC-003 — Invio WhatsApp con Template

CampoValore
IDUC-003
ObiettivoInviare un messaggio WhatsApp Business tramite template approvato da Meta
CanaleWhatsApp
ComplessitàBase
Tempo stimato15 minuti
API coinvoltePOST /api/message-server/whatsapp/send, GET /api/partner-gateway/v1/messages/status/{customerMessageId}

Scenari reali

  • OTP verification: BancaSicura invia un codice di verifica per confermare l'identita del cliente durante l'accesso all'home banking.
  • Appointment reminder: Studio Medico Verdi invia un promemoria appuntamento 24 ore prima, con data, ora e indirizzo della struttura.
  • Order update: FashionStore notifica il cliente che l'ordine e stato spedito, con link al tracking del corriere.

Ciclo di vita del template

Il template deve essere approvato da Meta prima di poterlo usare per l'invio. L'approvazione avviene una sola volta e puo richiedere da pochi minuti a 24 ore.

Step 1 — Identifica il template ID

Prima di inviare, devi conoscere l'id del template approvato. Puoi trovarlo nel pannello della piattaforma oppure via API:

curl -X GET "https://lora-api.agiletelecom.com/api/message-server/whatsapp/templates?status=APPROVED&phoneNumberId=5&limit=10" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Lista template approvati

{
"data": [
{
"id": 42,
"name": "order_shipped",
"language": "it",
"category": "UTILITY",
"status": "APPROVED",
"components": [
{
"type": "HEADER",
"format": "IMAGE"
},
{
"type": "BODY",
"text": "Ciao {{1}}, il tuo ordine {{2}} e stato spedito! Tracking: {{3}}"
},
{
"type": "FOOTER",
"text": "FashionStore - Assistenza clienti"
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "URL",
"text": "Traccia spedizione",
"url": "https://fashionstore.it/tracking/{{1}}"
}
]
}
]
},
{
"id": 58,
"name": "appointment_reminder",
"language": "it",
"category": "UTILITY",
"status": "APPROVED",
"components": [
{
"type": "BODY",
"text": "Gentile {{1}}, le ricordiamo l'appuntamento del {{2}} alle ore {{3}} presso {{4}}."
}
]
}
]
}
Dietro le quinte — Categorie template Meta

Meta classifica i template in tre categorie con regole e costi diversi:

CategoriaUsoEsempi
UTILITYMessaggi transazionali richiesti dall'utenteConferme ordine, aggiornamenti spedizione, promemoria
AUTHENTICATIONCodici OTP e verifica identitaCodici di accesso, verifica in due fattori
MARKETINGComunicazioni promozionaliOfferte, newsletter, inviti ad eventi

I template AUTHENTICATION hanno una struttura speciale con il bottone "Copia codice" integrato. I template MARKETING richiedono che l'utente abbia dato il consenso esplicito (opt-in).

Step 2 — Invia il messaggio con placeholder

Usa il template order_shipped (id: 42) con i placeholder valorizzati e un'immagine header:

curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42,
"mediaUrl": "https://cdn.fashionstore.it/orders/box-shipped.jpg"
},
"placeholders": {
"1": "Marco",
"2": "#ORD-20260409",
"3": "https://corriere.it/track/BRT789456123"
},
"enableNotification": true
}'

Response — Messaggio accettato

{
"messageId": "b83c2f1a-9d4e-4b12-8c7f-3e5a1d2b4c6e",
"simulation": false,
"results": {
"whatsapp": {
"accepted": true
},
"rcs": null,
"sms": null
}
}
Dietro le quinte — Come vengono risolti i placeholder

I placeholder nel template Meta usano la sintassi {{1}}, {{2}}, ecc. Nella request API, li mappi con chiavi numeriche:

  • "1": "Marco" sostituisce {{1}} nel body del template
  • "2": "#ORD-20260409" sostituisce {{2}}
  • "3": "https://corriere.it/track/BRT789456123" sostituisce {{3}}

Se il template ha un bottone con URL dinamico (es. https://fashionstore.it/tracking/{{1}}), il placeholder del bottone usa lo stesso sistema numerico ma con scope separato.

Il campo mediaUrl nel template object viene usato per sostituire l'header IMAGE del template. L'immagine deve essere accessibile pubblicamente via HTTPS.

:::warning Finestra delle 24 ore I messaggi template possono essere inviati in qualsiasi momento. I messaggi free-form (body) possono essere inviati solo entro 24 ore dall'ultimo messaggio ricevuto dall'utente. Fuori dalla finestra, usa sempre un template. :::

Step 3 — Verifica la consegna

curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/messages/status/b83c2f1a-9d4e-4b12-8c7f-3e5a1d2b4c6e?channel=WHATSAPP" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Consegnato e letto

{
"customerMessageId": "b83c2f1a-9d4e-4b12-8c7f-3e5a1d2b4c6e",
"channel": "WHATSAPP",
"destination": "+393401234567",
"deliveryStatus": "DELIVERED",
"deliveryStatusDescription": "Message delivered",
"sendDate": "2026-04-09T14:00:00+02:00",
"deliveryDate": "2026-04-09T14:00:01+02:00",
"readDate": "2026-04-09T14:02:30+02:00"
}
Dietro le quinte — Webhook WhatsApp

Per WhatsApp ricevi gli stessi tipi di callback di RCS:

DELIVERY:

{
"channel": "WHATSAPP",
"eventType": "DELIVERY",
"messageId": "b83c2f1a-9d4e-4b12-8c7f-3e5a1d2b4c6e",
"destination": "+393401234567",
"statusCode": 3,
"description": "delivered",
"eventDate": "2026-04-09T14:00:01Z"
}

READ:

{
"channel": "WHATSAPP",
"eventType": "READ",
"messageId": "b83c2f1a-9d4e-4b12-8c7f-3e5a1d2b4c6e",
"destination": "+393401234567",
"eventDate": "2026-04-09T14:02:30Z"
}

Configura il tuo endpoint nella guida Webhook.

Varianti

Template con bottoni tracked

Per tracciare i click sui bottoni URL del template, usa il placeholder shortLinkT1 che genera un link tracciato:

curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42
},
"placeholders": {
"1": "Giulia",
"2": "#ORD-20260410",
"3": "https://corriere.it/track/BRT111222333",
"shortLinkT1": "https://fashionstore.it/tracking/BRT111222333"
},
"enableNotification": true
}'

Template con header image

Se il template ha un header di tipo IMAGE, passa la mediaUrl dentro l'oggetto template:

curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393471234567",
"phoneNumberId": 5,
"template": {
"id": 58,
"mediaUrl": "https://cdn.studiomedico.it/logo-reminder.png"
},
"placeholders": {
"1": "Sig. Rossi",
"2": "10 aprile 2026",
"3": "15:30",
"4": "Studio Medico Verdi - Via Garibaldi 25, Roma"
},
"enableNotification": true
}'

Invio con fallback SMS

Se il destinatario non ha WhatsApp, il messaggio puo cadere automaticamente su SMS:

curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42
},
"placeholders": {
"1": "Marco",
"2": "#ORD-20260409",
"3": "https://corriere.it/track/BRT789456123"
},
"fallbackSms": {
"sender": "FStore",
"text": "Ciao Marco, il tuo ordine #ORD-20260409 e stato spedito! Tracking: https://corriere.it/track/BRT789456123"
},
"enableNotification": true
}'

Response — Fallback SMS attivato

{
"messageId": "c4d5e6f7-8901-2345-6789-abcdef012345",
"simulation": false,
"results": {
"whatsapp": {
"accepted": false,
"reasons": ["WhatsApp not available"]
},
"rcs": null,
"sms": {
"accepted": true,
"unicode": false,
"parts": 1,
"reasons": []
}
}
}

Errori comuni

Template non approvato

{
"status": "fail",
"data": {
"template": "Template 42 is not in APPROVED status"
}
}

Soluzione: Verifica che il template sia in stato APPROVED tramite il pannello o la API GET /whatsapp/templates?status=APPROVED.

phoneNumberId non valido

{
"status": "fail",
"data": {
"phoneNumberId": "Phone number not found or not associated with your account"
}
}

Soluzione: Usa GET /whatsapp/phone-numbers per ottenere gli ID dei numeri WhatsApp Business associati al tuo account.

Placeholder mancanti

Se il template richiede placeholder che non sono stati forniti, il messaggio viene rifiutato. Verifica la struttura del template e fornisci tutti i valori necessari.

Risultato atteso

StepAzioneRisultato
1GET /whatsapp/templatesTemplate id e struttura placeholder
2POST /whatsapp/sendmessageId restituito, accepted: true
3GET /messages/status/{id}deliveryStatus: "DELIVERED", readDate presente

Prossimi passi