Integra WhatsApp nella tua applicazione tramite semplici chiamate REST.
http://www.telmio.it/api/v1
Ogni richiesta deve includere la tua API key nell'header Authorization.
Tutte le richieste e risposte usano Content-Type: application/json.
Tutti gli endpoint supportano richieste cross-origin.
Genera la tua API key dalla Dashboard → API Keys e includila in ogni richiesta:
Authorization: Bearer wa_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
In alternativa, puoi passare la chiave come query parameter ?api_key= (sconsigliato per produzione) oppure nel body JSON come campo api_key.
Tutte le risposte di errore hanno lo stesso schema:
{
"success": false,
"error": "Descrizione dell'errore"
}
| HTTP Status | Significato |
|---|---|
200 | Successo |
400 | Parametri mancanti o non validi |
401 | API key mancante o non valida |
403 | API key disabilitata o consenso mancante |
405 | Metodo HTTP non supportato |
502 | Errore downstream (sistema WhatsApp) |
Invia un messaggio WhatsApp (testo o media) a un numero di telefono.
| Campo | Tipo | Richiesto | Descrizione |
|---|---|---|---|
phone | string | required | Numero in formato internazionale senza + (es: 393312345678) |
message | string | optional | Testo del messaggio. Obbligatorio se non si invia un media. |
media_url | string | optional | URL pubblico del file media da inviare. Alternativo a media_base64. |
media_base64 | string | optional | Contenuto del file media codificato in Base64. Alternativo a media_url. Max 16 MB decoded. |
media_mime | string | optional | MIME type del file (es: image/jpeg, application/pdf). Obbligatorio con media_base64. |
media_type | string | optional | Tipo media: image video audio document. Obbligatorio con media_url o media_base64. |
media_caption | string | optional | Didascalia per immagini e video. |
media_filename | string | optional | Nome del file (utile per documenti). |
force_consent | bool | optional | Se true invia il messaggio anche se il contatto non ha ancora dato il consenso. Default: false. Usare con attenzione: rispettare le normative GDPR/Privacy. |
POST http://www.telmio.it/api/v1/messages/send
Authorization: Bearer wa_xxxx
Content-Type: application/json
{
"phone": "393312345678",
"message": "Ciao! Come possiamo aiutarti?"
}
POST http://www.telmio.it/api/v1/messages/send
Authorization: Bearer wa_xxxx
Content-Type: application/json
{
"phone": "393312345678",
"media_url": "https://example.com/promo.jpg",
"media_type": "image",
"media_caption": "La nostra offerta speciale!"
}
POST http://www.telmio.it/api/v1/messages/send
Authorization: Bearer wa_xxxx
Content-Type: application/json
{
"phone": "393312345678",
"media_base64": "/9j/4AAQSkZJRgABAQAA...",
"media_mime": "image/jpeg",
"media_type": "image",
"media_caption": "La nostra offerta speciale!"
}
// media_base64: contenuto del file codificato in Base64 (max 16 MB)
// media_mime: MIME type del file (obbligatorio con media_base64)
POST http://www.telmio.it/api/v1/messages/send
Authorization: Bearer wa_xxxx
Content-Type: application/json
{
"phone": "393312345678",
"media_url": "https://example.com/catalogo.pdf",
"media_type": "document",
"media_filename": "catalogo-2026.pdf",
"media_caption": "Il nostro catalogo aggiornato"
}
POST http://www.telmio.it/api/v1/messages/send
Authorization: Bearer wa_xxxx
Content-Type: application/json
{
"phone": "393312345678",
"media_base64": "JVBERi0xLjQKJ...",
"media_mime": "application/pdf",
"media_type": "document",
"media_filename": "catalogo-2026.pdf",
"media_caption": "Il nostro catalogo aggiornato"
}
// media_base64: contenuto del file codificato in Base64 (max 16 MB)
// media_mime: MIME type del file (obbligatorio con media_base64)
curl -X POST 'http://www.telmio.it/api/v1/messages/send' \
-H 'Authorization: Bearer wa_xxxx' \
-H 'Content-Type: application/json' \
-d '{"phone":"393312345678","message":"Ciao!"}'
POST http://www.telmio.it/api/v1/messages/send
Authorization: Bearer wa_xxxx
Content-Type: application/json
{
"phone": "393312345678",
"message": "Ciao! Ti contatto per informarti sulla nostra offerta.",
"force_consent": true
}
{
"success": true,
"message_id": "3EB09762AC334B998BA875"
}
Invia la richiesta di consenso marketing a un numero. Se il contatto non esiste viene creato automaticamente. Il sistema usa il messaggio di consenso configurato nelle impostazioni.
| Campo | Tipo | Richiesto | Descrizione |
|---|---|---|---|
phone | string | required | Numero in formato internazionale senza + (es: 393312345678) |
first_name | string | optional | Nome (usato se il contatto non esiste ancora) |
last_name | string | optional | Cognome (usato se il contatto non esiste ancora) |
force | bool | optional | Se true invia il messaggio anche se già inviato in precedenza. Default: false |
POST http://www.telmio.it/api/v1/consent/send
Authorization: Bearer wa_xxxx
Content-Type: application/json
{
"phone": "393312345678",
"first_name": "Mario",
"last_name": "Rossi"
}
curl -X POST 'http://www.telmio.it/api/v1/consent/send' \
-H 'Authorization: Bearer wa_xxxx' \
-H 'Content-Type: application/json' \
-d '{"phone":"393312345678","first_name":"Mario","last_name":"Rossi"}'
{
"success": true,
"contact_id": 42,
"message_id": "3EB09762AC334B998BA875"
}
{
"success": true,
"skipped": true,
"reason": "consent_already_sent"
}
A differenza degli endpoint sopra (che tu chiami per inviare messaggi), questo è WAuto che chiama il tuo servizio: ogni messaggio in arrivo sul numero WhatsApp collegato viene inoltrato via POST all'URL che configuri, così un servizio esterno può leggerlo/interpretarlo (es. un bot, un CRM, un sistema di ticketing).
| Header | Valore |
|---|---|
Content-Type | application/json |
X-WhatsAuto-Signature |
sha256=<hmac> — HMAC-SHA256 del corpo della richiesta (raw JSON), calcolato con il tuo secret. Verifica sempre questa firma prima di elaborare la richiesta.
|
| Campo | Tipo | Descrizione |
|---|---|---|
event | string | Sempre "message.received" |
message_id | int|null | ID interno del messaggio in WAuto |
wa_message_id | string|null | ID del messaggio lato sistema WhatsApp |
from | string | Numero del mittente (senza @s.whatsapp.net) |
to | string|null | Numero/device che ha ricevuto il messaggio |
type | string | text audio image document |
body | string|null | Testo del messaggio (per gli audio, il testo trascritto) |
media_url | string|null | URL del media, se presente |
transcription | string|null | Trascrizione dell'audio, se disponibile (duplica body per i messaggi audio) |
timestamp | string | Data/ora del messaggio, YYYY-MM-DD HH:MM:SS |
POST https://tuo-servizio.example.com/webhook
Content-Type: application/json
X-WhatsAuto-Signature: sha256=5d41402abc4b2a76b9719d911017c59...
{
"event": "message.received",
"message_id": 1042,
"wa_message_id": "3EB09762AC334B998BA875",
"from": "393312345678",
"to": "393209269241",
"type": "text",
"body": "Vorrei prenotare per domani alle 15",
"media_url": null,
"transcription": null,
"timestamp": "2026-07-19 14:32:10"
}
Qualsiasi risposta HTTP 2xx entro 10 secondi è considerata un successo (il corpo della risposta viene ignorato).
Se il tuo servizio non risponde in tempo o restituisce un errore, WAuto registra il fallimento nei log ma
non ritenta automaticamente l'invio e continua a elaborare il messaggio normalmente (il webhook non blocca mai il resto del flusso).
const crypto = require('crypto');
function isValidSignature(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}
// Express: usa express.raw() o un middleware che ti dia il body grezzo,
// la firma va calcolata sul JSON esattamente come arrivato, non su un oggetto ri-serializzato.
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-whatsauto-signature'] || '';
if (!isValidSignature(req.body, signature, process.env.WHATSAUTO_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const message = JSON.parse(req.body);
console.log('Nuovo messaggio:', message);
res.sendStatus(200);
});
import hashlib
import hmac
def is_valid_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header)
# Flask
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-WhatsAuto-Signature', '')
if not is_valid_signature(request.get_data(), signature, WHATSAUTO_WEBHOOK_SECRET):
return 'Invalid signature', 401
message = request.get_json()
print('Nuovo messaggio:', message)
return '', 200
<?php
$rawBody = file_get_contents('php://input');
$signatureHeader = $_SERVER['HTTP_X_WHATSAUTO_SIGNATURE'] ?? '';
$secret = getenv('WHATSAUTO_WEBHOOK_SECRET');
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $signatureHeader)) {
http_response_code(401);
exit('Invalid signature');
}
$message = json_decode($rawBody, true);
error_log('Nuovo messaggio: ' . print_r($message, true));
http_response_code(200);
const WHATSAUTO_KEY = 'wa_xxxx';
const API_BASE = 'http://www.telmio.it/api/v1';
async function sendMessage(phone, message) {
const res = await fetch(`${API_BASE}/messages/send`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${WHATSAUTO_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ phone, message })
});
return res.json();
}
async function sendConsent(phone, firstName, lastName) {
const res = await fetch(`${API_BASE}/consent/send`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${WHATSAUTO_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ phone, first_name: firstName, last_name: lastName })
});
return res.json();
}
// Uso
sendMessage('393312345678', 'Ciao dal nostro sistema!').then(console.log);
import requests
WHATSAUTO_KEY = 'wa_xxxx'
API_BASE = 'http://www.telmio.it/api/v1'
headers = {
'Authorization': f'Bearer {WHATSAUTO_KEY}',
'Content-Type': 'application/json'
}
def send_message(phone: str, message: str):
r = requests.post(f'{API_BASE}/messages/send',
headers=headers,
json={'phone': phone, 'message': message})
r.raise_for_status()
return r.json()
def send_consent(phone: str, first_name='', last_name=''):
r = requests.post(f'{API_BASE}/consent/send',
headers=headers,
json={'phone': phone, 'first_name': first_name, 'last_name': last_name})
r.raise_for_status()
return r.json()
# Uso
print(send_message('393312345678', 'Ciao dal nostro sistema!'))
<?php
define('WHATSAUTO_KEY', 'wa_xxxx');
define('API_BASE', 'http://www.telmio.it/api/v1');
function whatsauto_request(string $endpoint, array $data): array {
$ch = curl_init(API_BASE . $endpoint);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . WHATSAUTO_KEY,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($data),
]);
$body = curl_exec($ch);
curl_close($ch);
return json_decode($body, true);
}
// Invia messaggio
$r = whatsauto_request('/messages/send', [
'phone' => '393312345678',
'message' => 'Ciao dal nostro sistema!',
]);
print_r($r);
// Invia consenso
$r = whatsauto_request('/consent/send', [
'phone' => '393312345678',
'first_name' => 'Mario',
'last_name' => 'Rossi',
]);
print_r($r);