Scambi client_id e client_secret con un token Bearer valido un'ora, solo server-to-server.
← Torna alla documentazione API
La prima fattura in 6 passi
- Crea la credenziale nel pannello, in Fatturazione → Impostazioni → Accesso API, e copia subito il client_secret: viene mostrato una sola volta.
- Invia POST /v1/auth/token con grant_type client_credentials, client_id e client_secret.
- Ricevi access_token, token_type Bearer, expires_in 3600 e l’elenco degli scope concessi.
- Inserisci il token in un header Authorization: Bearer <access_token> in tutte le altre chiamate.
- Verifica cosa hai effettivamente ottenuto con GET /v1/me: tenant, scope e limiti di frequenza correnti.
Tutti gli endpoint
| Metodo | Endpoint | Scope | Idempotency-Key | Richieste / minuto |
|---|---|---|---|---|
| POST | /auth/token Scambia le credenziali con un token di accesso | — | — | 120 |
| GET | /me Tenant, scope e limiti attuali | invoices:read | — | 120 |
Cos'è l'API 4invoices
bash
curl -sS -X POST https://api.4invoices.net/v1/auth/token \
-H 'Content-Type: application/json' \
-d '{
"grant_type": "client_credentials",
"client_id": "cli_XXXXXXXXXXXX",
"client_secret": "sec_XXXXXXXXXXXXXXXXXXXX"
}'
# → {"access_token":"eyJ...","token_type":"Bearer","expires_in":3600,
# "scope":"invoices:read invoices:write efactura:submit"}bash
curl -sS https://api.4invoices.net/v1/me \
-H "Authorization: Bearer $ACCESS_TOKEN"
# → tenant, scope concessi e bucket di frequenza attualijavascript
// Metti in cache il token; non generarne uno per ogni richiesta.
let cached = { token: "", expiresAt: 0 };
async function getToken() {
if (cached.token && Date.now() < cached.expiresAt - 60_000) return cached.token;
const res = await fetch("https://api.4invoices.net/v1/auth/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_id: process.env.FOURINVOICES_CLIENT_ID,
client_secret: process.env.FOURINVOICES_CLIENT_SECRET,
}),
});
if (!res.ok) throw new Error(`token ${res.status}`);
const data = await res.json();
cached = { token: data.access_token, expiresAt: Date.now() + data.expires_in * 1000 };
return cached.token;
}https://api.4invoices.net/v1 · https://api.4invoices.net/v1/openapi.json
Scope
- invoices:read
- invoices:write
- clients:read
- clients:write
- efactura:read
- efactura:submit
Solo server-to-server. Non chiamare l'API da JavaScript di browser: il client_secret arriverebbe al visitatore e CORS blocca comunque ogni origin.
Errori
| Stato | Tipo | Codice |
|---|---|---|
| 401 | authentication_error | invalid_client |
| 401 | authentication_error | token_expired |
| 401 | authentication_error | invalid_token |
| 403 | permission_error | insufficient_scope |
Errori frequenti
- L’endpoint del token ha un proprio limite per IP. Un token per processo, rinnovato prima della scadenza, non uno per richiesta.
- Il client_secret viene memorizzato solo come hash; se lo perdi, crei una nuova credenziale e revochi quella vecchia.
- Crea credenziali separate per l’ERP, il negozio e gli script interni, ciascuna con scope minimi. Revocarne una non incide sulle altre.
- CORS non consente alcuna origine browser: l’API è pensata per l’uso server-to-server.
Domande e risposte per sviluppatori
Cosa succede se il client_secret è errato?
Ricevi un 401 con codice invalid_client. Un secret troppo corto fallisce prima, in fase di validazione, con 422 validation_failed e param client_secret.
Esiste un ambiente di test separato?
No. Esiste un unico host di produzione. Esegui i test con le fatture proforma (document_kind proforma) e con /invoices/preview-totals, che non consuma alcun numero fiscale.
Posso restringere gli scope di una credenziale esistente?
Sì, dal pannello. I token già emessi mantengono gli scope con cui sono stati generati fino alla scadenza, entro un’ora.