Autenticazione e API Key
Gestire le API key e autenticare le richieste
Ogni richiesta all'API di Tratto si autentica con un bearer token nell'header
Authorization. Ce ne sono di due tipi:
- una chiave API, per le tue integrazioni: server, script e SDK. Quasi tutta questa pagina parla delle chiavi;
- una sessione della dashboard, il token di una persona che ha effettuato
l'accesso, che la dashboard invia per te. Alcune rotte appartengono alla
persona e non a un workspace (elencare, creare ed eliminare workspace,
invitare e rimuovere membri) e accettano solo una sessione: con una chiave API
rispondono
403. Vedi Header del Workspace.
Formato della API Key
Le API key di Tratto seguono questo formato:
tratto_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
tratto_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx- Prefisso:
tratto_live_(consegna reale) otratto_test_(simulata, vedi Test mode) - Seguito da 32 caratteri casuali
- Usato come bearer token nell'header
Authorization
L'ambiente è scritto nella chiave: una chiave di test esegue l'intera pipeline senza inviare email reali, vede solo i dati di test, e viene rifiutata dagli endpoint che raggiungono destinatari reali.
Header di Autenticazione
Includi la tua API key in ogni richiesta:
Authorization: Bearer tratto_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxEsempio:
curl https://api.tratto.email/v1/emails \
-H "Authorization: Bearer tratto_live_..."Senza l'header, riceverai 401 Unauthorized.
Permessi
Ogni chiave porta con sé un insieme di permessi, applicati ad ogni richiesta: una chiave a cui manca il permesso richiesto da un endpoint riceve 403 Forbidden, indipendentemente dal workspace a cui appartiene.
| Permesso | Consente |
|---|---|
emails:send | Inviare email, programmare, annullare, riprogrammare |
emails:read | Leggere il log email e gli eventi di consegna |
contacts:read / contacts:write | Leggere / creare, aggiornare, importare contatti e audience |
domains:read / domains:write | Leggere / aggiungere, verificare, rimuovere domini di invio |
templates:read / templates:write | Leggere / creare e modificare template |
campaigns:read / campaigns:write | Leggere / creare e inviare campagne e flow |
webhooks:read / webhooks:write | Leggere / registrare, modificare, ruotare endpoint webhook |
api-keys:read / api-keys:write | Leggere / creare, modificare, revocare API key |
billing:read / billing:write | Leggere piano e consumi / avviare checkout e portale fatturazione |
workspace:write | Modificare le impostazioni del workspace, compresi il mittente generale e i mittenti per tipo |
members:write | Nessuna rotta lo usa: PATCH /v1/workspace/members/:userId, che cambiava il ruolo di un membro, non esiste più e risponde 404. Invitare e rimuovere membri si fa solo dalla dashboard: ogni chiave API riceve 403 (vedi Team) |
* | Accesso completo — tutti i permessi sopra, inclusi quelli futuri |
Concedi l'insieme più ristretto che basta allo scopo. Una chiave che invia solo email transazionali ha bisogno di emails:send e nient'altro; se rispecchia anche le iscrizioni nella tua lista contatti serve pure contacts:write.
* viene memorizzato da solo: elencarlo insieme ai permessi granulari è ridondante, dato che li copre già.
Crea una API Key
Genera una nuova API key tramite l'API, oppure da Impostazioni → API key nella dashboard.
name, env e permissions sono tutti obbligatori. Ometterne permissions (o passare un array vuoto) restituisce 422.
cURL
curl -X POST https://api.tratto.email/v1/api-keys \
-H "Authorization: Bearer tratto_live_CHIAVE_ESISTENTE" \
-H "Content-Type: application/json" \
-d '{"name":"production","env":"live","permissions":["emails:send"]}'Node.js
const response = await fetch('https://api.tratto.email/v1/api-keys', {
method: 'POST',
headers: {
'Authorization': 'Bearer tratto_live_CHIAVE_ESISTENTE',
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'production', env: 'live', permissions: ['emails:send'] }),
});
const { data } = await response.json();
console.log('Nuova API Key:', data.key);Python
import requests
response = requests.post(
'https://api.tratto.email/v1/api-keys',
headers={
'Authorization': 'Bearer tratto_live_CHIAVE_ESISTENTE',
'Content-Type': 'application/json',
},
json={'name': 'production', 'env': 'live', 'permissions': ['emails:send']},
)
api_key = response.json()['data']['key']
print(f"Nuova API Key: {api_key}")PHP
// tratto/email non ha metodi per le API key: HTTP con ext-curl
$ch = curl_init('https://api.tratto.email/v1/api-keys');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer tratto_live_CHIAVE_ESISTENTE',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['name' => 'production', 'env' => 'live', 'permissions' => ['emails:send']]),
CURLOPT_RETURNTRANSFER => true,
]);
$apiKey = json_decode(curl_exec($ch), true)['data']['key'];
echo "Nuova API Key: {$apiKey}\n";Risposta:
{
"data": {
"id": "key_abc123",
"name": "production",
"key": "tratto_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"prefix": "tratto_live_xxxx...xxxx",
"env": "live",
"permissions": ["emails:send"],
"createdAt": "2025-06-30T12:00:00Z",
"lastUsedAt": null,
"revokedAt": null
}
}⚠️ Importante: Il campo key è mostrato una sola volta. Salvalo immediatamente: non verrà più visualizzato. Se lo perdi, revoca e crea una nuova chiave.
Elenca le API Key
Recupera tutte le API key per il tuo tenant.
cURL
curl https://api.tratto.email/v1/api-keys \
-H "Authorization: Bearer tratto_live_..."Node.js
const response = await fetch('https://api.tratto.email/v1/api-keys', {
headers: {
'Authorization': 'Bearer tratto_live_...',
},
});
const { data } = await response.json();
console.log(data); // Array di oggetti API keyPython
import requests
response = requests.get(
'https://api.tratto.email/v1/api-keys',
headers={'Authorization': 'Bearer tratto_live_...'},
)
keys = response.json()['data']
for key in keys:
print(f"Key: {key['prefix']} (Creata: {key['createdAt']})")PHP
// tratto/email non ha metodi per le API key: HTTP con ext-curl
$ch = curl_init('https://api.tratto.email/v1/api-keys');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer tratto_live_...'],
CURLOPT_RETURNTRANSFER => true,
]);
$keys = json_decode(curl_exec($ch), true)['data'];
foreach ($keys as $key) {
echo "Key: {$key['prefix']} (Creata: {$key['createdAt']})\n";
}Risposta:
{
"data": [
{
"id": "key_abc123",
"name": "production",
"prefix": "tratto_live_xxxx...xxxx",
"createdAt": "2025-06-30T12:00:00Z",
"lastUsedAt": "2025-06-30T13:45:00Z"
},
{
"id": "key_def456",
"name": "development",
"prefix": "tratto_live_yyyy...yyyy",
"createdAt": "2025-06-29T10:00:00Z",
"lastUsedAt": "2025-06-29T15:20:00Z"
}
]
}Nota: La chiave completa non è mai restituita dopo la creazione, solo il prefisso (primi e ultimi 4 caratteri).
Modifica i permessi di una chiave
Cambia i permessi di una chiave esistente, senza revocarla né ruotare il segreto. Il valore della chiave non cambia, quindi nulla di ciò che la usa va rideployato — i permessi vengono letti ad ogni richiesta e il nuovo insieme vale già dalla successiva.
cURL
curl -X PATCH https://api.tratto.email/v1/api-keys/key_abc123 \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"permissions":["emails:send","contacts:write"]}'Node.js
const response = await fetch('https://api.tratto.email/v1/api-keys/key_abc123', {
method: 'PATCH',
headers: {
'Authorization': 'Bearer tratto_live_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({ permissions: ['emails:send', 'contacts:write'] }),
});
const { data } = await response.json();
console.log('Permessi:', data.permissions);Python
import requests
response = requests.patch(
'https://api.tratto.email/v1/api-keys/key_abc123',
headers={
'Authorization': 'Bearer tratto_live_...',
'Content-Type': 'application/json',
},
json={'permissions': ['emails:send', 'contacts:write']},
)
print(f"Permessi: {response.json()['data']['permissions']}")PHP
// tratto/email non ha metodi per le API key: HTTP con ext-curl
$ch = curl_init('https://api.tratto.email/v1/api-keys/key_abc123');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer tratto_live_...',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['permissions' => ['emails:send', 'contacts:write']]),
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
echo 'Permessi: ', implode(', ', $data['permissions']), "\n";permissions sostituisce l'insieme precedente, non ci si fonde. Invia la lista completa che vuoi ottenere.
Richiede api-keys:write. Altre risposte:
| Stato | Quando |
|---|---|
409 | La chiave è revocata — i permessi non sono più modificabili. Creane una nuova. |
422 | Permesso sconosciuto, lista vuota, o tentativo di rimuovere api-keys:write dalla chiave che sta facendo la richiesta. |
Non puoi togliere api-keys:write dalla chiave con cui ti stai autenticando: nessun altro endpoint potrebbe restituirtelo, quindi resteresti chiuso fuori dalla gestione delle chiavi. Rimuoverlo da una chiave diversa è consentito — quello è recuperabile.
Revoca una API Key
Revoca immediatamente una API key per impedirne l'uso.
cURL
curl -X DELETE https://api.tratto.email/v1/api-keys/key_abc123 \
-H "Authorization: Bearer tratto_live_..."Node.js
const response = await fetch('https://api.tratto.email/v1/api-keys/key_abc123', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer tratto_live_...',
},
});
const { data } = await response.json();
console.log('Revocata:', data.id);Python
import requests
response = requests.delete(
'https://api.tratto.email/v1/api-keys/key_abc123',
headers={'Authorization': 'Bearer tratto_live_...'},
)
print(f"Revocata: {response.json()['data']['id']}")PHP
// tratto/email non ha metodi per le API key: HTTP con ext-curl
$ch = curl_init('https://api.tratto.email/v1/api-keys/key_abc123');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => ['Authorization: Bearer tratto_live_...'],
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
echo "Revocata: {$data['id']}\n";Una volta revocata, le richieste con quella chiave restituiranno 401 Unauthorized.
Best Practice di Sicurezza delle Chiavi
1. Non Esporre le Chiavi Client-Side
Le API key concedono accesso completo al workspace. Non includerle mai in:
- JavaScript frontend (React, Vue, Angular)
- App mobile (iOS, Android)
- Codice sorgente pubblicato su GitHub
Invece, chiama la tua API backend, che tiene la chiave al sicuro.
Per indicazioni specifiche per framework vedi React (Server Component e Server Action) e Angular (SSR e AnalogJS/Nitro).
Sbagliato:
// ❌ NON FARE QUESTO MAI
const trattoKey = 'tratto_live_...';
const response = await fetch('https://api.tratto.email/v1/emails', {
headers: { 'Authorization': `Bearer ${trattoKey}` },
});Corretto:
// ✅ Chiama il tuo backend
const response = await fetch('/api/send-email', {
method: 'POST',
body: JSON.stringify({ to, subject, text }),
});2. Tratta le Chiavi come Password
- Memorizza in variabili di ambiente (
.env.local, non.env) - Usa la gestione dei segreti per la produzione (GitHub Secrets, HashiCorp Vault, ecc.)
- Non commitarle su Git
3. Ruota le Chiavi Regolarmente
- Crea una nuova chiave
- Aggiorna i tuoi servizi per usare la nuova chiave
- Aspetta che tutti i deployment finiscano
- Revoca la vecchia chiave
4. Usa Chiavi Specifiche per gli Ambienti
Crea chiavi separate per:
production: Usata solo in produzionestaging: Usata solo in stagingdevelopment: Usata solo nello sviluppo locale
In questo modo, una chiave di sviluppo compromessa non compromette la produzione.
5. Monitora l'Uso delle Chiavi
Controlla lastUsedAt nelle risposte di elenco per identificare chiavi non utilizzate. Revoca periodicamente le chiavi vecchie non utilizzate.
Risposte di Errore
401 Unauthorized
Causa: Credenziali mancanti o non valide: una chiave API errata o revocata, oppure una sessione della dashboard scaduta.
{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing or invalid Authorization header",
"docs": "https://docs.tratto.email/it/authentication"
}
}Fix:
- Assicurati che l'header
Authorization: Bearer tratto_live_...sia presente - Controlla per errori di digitazione nella API key
- Verifica che la chiave non sia stata revocata
- Nella dashboard, accedi di nuovo
403 Forbidden
Causa: La API key è valida ma non ha permesso per questa operazione.
{
"error": {
"code": "FORBIDDEN",
"message": "Your API key does not have permission to perform this action",
"docs": "https://docs.tratto.email/it/authentication"
}
}La risposta nomina il permesso mancante, così sai quale aggiungere:
{
"error": {
"code": "FORBIDDEN",
"message": "Missing required permission: contacts:write",
"suggestion": "Create a new API key with the 'contacts:write' permission."
}
}Si risolve concedendo quel permesso alla chiave — vedi Modifica i permessi di una chiave — oppure usando una chiave che lo ha già. Controlla i permessi correnti con GET /v1/api-keys.
Nella dashboard, un membro del workspace che non è il proprietario riceve 403 con Only the workspace owner can do this. su chiavi API, webhook, billing, modifiche ai domini e impostazioni del workspace, qualunque permesso abbia. Vedi Team.
Header del Workspace
Una richiesta autenticata con una sessione della dashboard (un ID token Firebase, come fa la dashboard quando chiama l'API) può aggiungere l'header facoltativo Tratto-Workspace per scegliere su quale workspace operare, fra quelli a cui l'account ha accesso: quelli di cui è proprietario e quelli in cui è membro attivo.
Tratto-Workspace: ws_xxxxxxxxxxxxEsempio:
curl https://api.tratto.email/v1/workspace \
-H "Authorization: Bearer $FIREBASE_ID_TOKEN" \
-H "Tratto-Workspace: ws_..."- Senza l'header, la richiesta opera sul workspace predefinito dell'account.
- Con una chiave API l'header è ignorato: una chiave appartiene a un solo workspace e opera sempre su quello.
- Non c'è ripiego. Un header che indica un workspace a cui l'account non ha accesso viene rifiutato, non reindirizzato su un altro workspace:
403 NOT_A_MEMBERse l'account non ne è proprietario né membro attivo,403 TENANT_CLOSEDse il workspace è stato eliminato. Un valore che non è un id di workspace riceve422 VALIDATION_ERROR. Vedi Codici di errore. - Un id di workspace è lungo da 1 a 128 caratteri fra
A-Z,a-z,0-9,_e-, e non inizia mai con__.
Le chiavi API restano il modo consigliato per integrare da un server. L'header serve agli strumenti che usano una sessione della dashboard, come la dashboard stessa e gli strumenti interni. Gli SDK non lo impostano.
Header di Idempotenza
L'header Idempotency-Key previene richieste duplicate su determinati endpoint (operazioni POST che modificano lo stato).
Uso:
POST /v1/emails
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000Regole:
- Il valore dovrebbe essere un UUID v4 (RFC 4122)
- Tratto mette in cache la risposta per 24 ore
- Se riprovi con la stessa chiave, ottieni la stessa risposta senza un'azione duplicata
- La risposta in cache viene restituita per ogni retry con quella chiave; il corpo non viene confrontato, quindi riusa una chiave solo per l'operazione che l'ha creata
Esempio:
import { v4 as uuidv4 } from 'uuid';
const idempotencyKey = uuidv4();
const response = await fetch('https://api.tratto.email/v1/emails', {
method: 'POST',
headers: {
'Authorization': 'Bearer tratto_live_...',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify({
from: 'hello@tuodominio.it',
to: 'user@example.com',
subject: 'Ciao',
text: 'Mondo',
}),
});Vedi Idempotenza per ulteriori dettagli.
Prossimi Passi
- Pronto a inviare? Vai a Invia Email
- Devi verificare i domini? Vedi Domini
- Comprendi tutti i codici di errore? Controlla Codici di Errore
Modifica questa pagina su GitHub
Ultimo aggiornamento