Ruil client_id en client_secret voor een Bearer-token van één uur, uitsluitend server-to-server.
← Terug naar de API-documentatie
Je eerste factuur in 6 stappen
- Maak de credential aan in het paneel onder Facturatie → Instellingen → API-toegang en kopieer het client_secret meteen — het wordt maar één keer getoond.
- Stuur POST /v1/auth/token met grant_type client_credentials, client_id en client_secret.
- U krijgt access_token, token_type Bearer, expires_in 3600 en de lijst met toegekende scopes terug.
- Zet het token in een Authorization: Bearer <access_token>-header bij elke andere aanroep.
- Controleer met GET /v1/me wat u werkelijk hebt gekregen: tenant, scopes en de huidige rate-buckets.
Alle endpoints
| Methode | Endpoint | Scope | Idempotency-Key | Verzoeken / minuut |
|---|---|---|---|---|
| POST | /auth/token Inloggegevens ruilen voor een toegangstoken | — | — | 120 |
| GET | /me Tenant, scopes en huidige limieten | invoices:read | — | 120 |
Wat de 4invoices-API is
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, toegekende scopes en de huidige rate-limit-budgettenjavascript
// Cache het token; vraag niet bij elk request een nieuw aan.
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
Scopes
- invoices:read
- invoices:write
- clients:read
- clients:write
- efactura:read
- efactura:submit
Alleen server-to-server. Roep de API nooit aan vanuit browser-JavaScript: het client_secret zou bij de bezoeker terechtkomen, en CORS blokkeert elke origin toch al.
Fouten
| Status | Type | Code |
|---|---|---|
| 401 | authentication_error | invalid_client |
| 401 | authentication_error | token_expired |
| 401 | authentication_error | invalid_token |
| 403 | permission_error | insufficient_scope |
Veelgemaakte fouten
- Het token-endpoint heeft een eigen limiet per IP. Eén token per proces, vernieuwd vóór het verloopt — niet één per request.
- Het client_secret wordt alleen als hash opgeslagen; raakt u het kwijt, dan maakt u een nieuwe credential aan en trekt u de oude in.
- Geef aparte credentials uit voor de ERP, de webshop en interne scripts, elk met minimale scopes. Het intrekken van één credential heeft geen invloed op de andere.
- CORS laat geen enkele browser-origin toe: de API is bewust server-to-server.
Vragen en antwoorden voor ontwikkelaars
Wat gebeurt er als het client_secret onjuist is?
U krijgt een 401 met code invalid_client. Een te kort secret faalt al eerder, bij de validatie, met 422 validation_failed en param client_secret.
Is er een aparte testomgeving?
Nee. Er is één productiehost. Test met proforma's (document_kind proforma) en met /invoices/preview-totals, dat geen fiscaal nummer verbruikt.
Kan ik de scopes van een bestaande credential beperken?
Ja, vanuit het paneel. Reeds uitgegeven tokens behouden de scopes waarmee ze zijn aangemaakt tot ze verlopen, binnen één uur.