Base URL e autenticazione
Sostituisci BASE con l'URL della tua installazione (es. https://TUO_SITO.it/api-push). Per le API protette invia gli header:
X-Willy-App-Id: IL_TUO_APP_ID + X-Willy-App-Key: LA_TUA_APP_KEY — autenticazione tramite appId + appKey negli header HTTP
Dominio gestito lato server: il client non invia mai un parametro domain. Il server ricava il dominio dall’appId nel proprio database e valida l’header Origin del browser. Nessun dato di dominio viene inviato dal client.
Content-Type per POST: Content-Type: application/json.
Nota: Il server ricava il dominio dall'app_id. Non inviare mai un dominio dal client.
Sicurezza e tenant: il server ricava il dominio dall'appId nel proprio database. L'header Origin del browser viene validato automaticamente. Ogni richiesta deve includere gli header X-Willy-App-Id e X-Willy-App-Key; il server associa l'appId al dominio corretto senza che il client invii alcun parametro di dominio. Per dettagli su rate limit e audit vedi api-push/SECURITY.md.
Esempi di chiamate
1. Config Firebase (GET)
cURL
curl -s "BASE/get-firebase-config.php"
JavaScript (fetch)
const config = await fetch(BASE + '/get-firebase-config.php').then(r => r.json());
if (config.error) throw new Error(config.error);
// config.apiKey, config.projectId, config.vapidKey, ...
PHP
$config = json_decode(file_get_contents('https://TUO_SITO.it/api-push/get-firebase-config.php'), true);
if (!empty($config['error'])) throw new Exception($config['error']);
Python
import requests
r = requests.get(BASE + '/get-firebase-config.php')
config = r.json()
if 'error' in config:
raise ValueError(config['error'])
2. Registrazione device (POST) – push normale
cURL
curl -X POST "BASE/api/register.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"push_token":"FCM_TOKEN_QUI","platform":"web","device_type":"web_browser","firebase_project_id":"tuo-project-id"}'
JavaScript (fetch)
await fetch(BASE + '/api/register.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Willy-App-Id': appId, 'X-Willy-App-Key': appKey },
body: JSON.stringify({
push_token: fcmToken,
platform: 'web',
device_type: 'web_browser',
firebase_project_id: firebase.app().options?.projectId || ''
})
});
PHP
$payload = [
'push_token' => $fcmToken,
'platform' => 'web',
'device_type' => 'web_browser',
'firebase_project_id' => $projectId
];
$ch = curl_init($base . '/api/register.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-Willy-App-Id: ' . $appId, 'X-Willy-App-Key: ' . $appKey],
CURLOPT_RETURNTRANSFER => true
]);
$res = curl_exec($ch);
Python
import requests
r = requests.post(BASE + '/api/register.php', json={
'push_token': fcm_token,
'platform': 'web',
'device_type': 'web_browser',
'firebase_project_id': project_id
}, headers={'X-Willy-App-Id': app_id, 'X-Willy-App-Key': app_key})
data = r.json()
3. Registrazione device con chiave pubblica (E2EE)
cURL
curl -X POST "BASE/api/register.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"push_token":"FCM_TOKEN","platform":"web","device_type":"web_browser","public_key":"BASE64URL_CHIAVE_PUBBLICA","firebase_project_id":"project-id"}'
JavaScript (fetch)
await fetch(BASE + '/api/register.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Willy-App-Id': appId, 'X-Willy-App-Key': appKey },
body: JSON.stringify({
push_token: token,
platform: 'web',
device_type: 'web_browser',
user_agent: navigator.userAgent,
public_key: publicKeyBase64,
firebase_project_id: window.firebase?.app()?.options?.projectId || ''
})
});
4. Lista device (GET) – limit e offset per paginazione
cURL
curl -s -H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" "BASE/api/list.php?app_id=IL_TUO_APP_ID&limit=100&offset=0"
curl -s -H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" "BASE/api/list.php?app_id=IL_TUO_APP_ID&platform=web&device_type=web_browser"
JavaScript
const res = await fetch(BASE + '/api/list.php?app_id=' + encodeURIComponent(appId) + '&limit=100&offset=0', {
headers: { 'X-Willy-App-Id': appId, 'X-Willy-App-Key': appKey }
});
const data = await res.json();
console.log(data.data.devices, data.data.count, data.data.total);
5. Lista device cifrati (GET) – richiede X-Willy-App-Id / X-Willy-App-Key
cURL
curl -s -H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" "BASE/api/list_encrypted.php?app_id=IL_TUO_APP_ID"
PHP
$ch = curl_init($base . '/api/list_encrypted.php?app_id=' . urlencode($appId));
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['X-Willy-App-Id: ' . $appId, 'X-Willy-App-Key: ' . $appKey],
CURLOPT_RETURNTRANSFER => true
]);
$json = json_decode(curl_exec($ch), true);
6. Statistiche (GET)
cURL
curl -s -H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" "BASE/api/stats.php?app_id=IL_TUO_APP_ID"
Risposta esempio
{
"success": true,
"data": {
"domain": "tuodominio.it",
"stats": {
"total_registrations": 10,
"total_active_devices": 8,
"total_inactive_devices": 2,
"total_push_sent": 150,
"total_push_failed": 3,
"total_invalidated_tokens": 1,
"last_cleanup_at": "2025-03-14 12:00:00",
"updated_at": "2025-03-14 12:00:00"
}
}
}
Nota: il campo domain nella risposta è ricavato dal server in base all'appId — non è un dato inviato dal client.
JavaScript
const res = await fetch(BASE + '/api/stats.php?app_id=' + encodeURIComponent(appId), {
headers: { 'X-Willy-App-Id': appId, 'X-Willy-App-Key': appKey }
});
const data = await res.json();
const stats = data.data.stats;
console.log('Inviati:', stats.total_push_sent, 'Falliti:', stats.total_push_failed);
Python
r = requests.get(BASE + '/api/stats.php', params={'app_id': app_id}, headers={'X-Willy-App-Id': app_id, 'X-Willy-App-Key': app_key})
stats = r.json()['data']['stats']
print('Inviati:', stats['total_push_sent'])
7. Invio singolo (POST) – richiede X-Willy-App-Id / X-Willy-App-Key
cURL
curl -X POST "BASE/api/send.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"title":"Titolo","body":"Corpo messaggio","url":"/pagina"}'
JavaScript
await fetch(BASE + '/api/send.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Willy-App-Id': appId,
'X-Willy-App-Key': appKey
},
body: JSON.stringify({
title: 'Titolo',
body: 'Corpo',
url: '/pagina',
target: {}
})
});
PHP
$body = [
'title' => 'Titolo',
'body' => 'Corpo',
'url' => '/pagina',
'target' => []
];
$ch = curl_init($base . '/api/send.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-Willy-App-Id: ' . $appId, 'X-Willy-App-Key: ' . $appKey],
CURLOPT_RETURNTRANSFER => true
]);
$res = curl_exec($ch);
Python
requests.post(BASE + '/api/send.php', json={
'title': 'Titolo', 'body': 'Corpo', 'url': '/pagina', 'target': {}
}, headers={'X-Willy-App-Id': app_id, 'X-Willy-App-Key': app_key})
8. Invio bulk (POST)
cURL
curl -X POST "BASE/api/send_bulk.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"title":"Bulk","body":"Messaggio","target":{},"limit":5000}'
PHP
$body = [
'title' => 'Bulk',
'body' => 'Messaggio',
'target' => [],
'limit' => 5000
];
$ch = curl_init($base . '/api/send_bulk.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-Willy-App-Id: ' . $appId, 'X-Willy-App-Key: ' . $appKey],
CURLOPT_RETURNTRANSFER => true
]);
$res = curl_exec($ch);
9. Invio cifrato E2EE (POST)
cURL
curl -X POST "BASE/api/send_encrypted.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"title":"Cifrato","body":"Solo questo device può decifrare.","url":"/","icon":"/logobase.png","target":{},"limit":5000}'
JavaScript
const res = await fetch(BASE + '/api/send_encrypted.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Willy-App-Id': appId,
'X-Willy-App-Key': appKey
},
body: JSON.stringify({
title: 'Cifrato',
body: 'Solo questo device può decifrare.',
url: '/',
icon: '/logobase.png',
target: {},
limit: 5000
})
});
const data = await res.json();
// data.data.sent, data.data.failed, data.data.invalidated, data.data.total
PHP
$body = [
'title' => 'Cifrato',
'body' => 'Solo questo device può decifrare.',
'url' => '/',
'icon' => '/logobase.png',
'target' => [],
'limit' => 5000
];
$ch = curl_init($base . '/api/send_encrypted.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-Willy-App-Id: ' . $appId, 'X-Willy-App-Key: ' . $appKey],
CURLOPT_RETURNTRANSFER => true
]);
$res = curl_exec($ch);
Python
r = requests.post(BASE + '/api/send_encrypted.php', json={
'title': 'Cifrato',
'body': 'Solo questo device può decifrare.',
'url': '/', 'icon': '/logobase.png', 'target': {}, 'limit': 5000
}, headers={'X-Willy-App-Id': app_id, 'X-Willy-App-Key': app_key})
print(r.json()['data']['sent'], r.json()['data']['failed'])
10. Rimuovi device (POST) – token_hash da list o list_encrypted
cURL (normale)
curl -X POST "BASE/api/delete_device.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"token_hash":"abc123def456"}'
cURL (cifrato)
curl -X POST "BASE/api/delete_encrypted_device.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"token_hash":"abc123def456"}'
11. Disiscrivi (unregister) – con push_token
cURL
curl -X POST "BASE/api/unregister.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"push_token":"FCM_TOKEN","reason":"user"}'
12. Heartbeat
cURL
curl -X POST "BASE/api/heartbeat.php" \
-H "Content-Type: application/json" \
-H "X-Willy-App-Id: IL_TUO_APP_ID" -H "X-Willy-App-Key: LA_TUA_APP_KEY" \
-d '{"push_token":"FCM_TOKEN"}'
13. Verifica Firebase (GET) – solo admin
cURL
curl -s -H "X-API-TOKEN: WILLY_ADMIN_TOKEN" "BASE/api/firebase_check.php"