Zamijenite client_id i client_secret za Bearer token koji traje sat, samo server-to-server.
Prva faktura u 6 koraka
- Generirajte vjerodajnicu u panelu, pod Fakturiranje → Postavke → API pristup, i odmah kopirajte client_secret — prikazuje se samo jednom.
- Pošaljite POST /v1/auth/token s grant_type client_credentials, client_id i client_secret.
- Natrag dobivate access_token, token_type Bearer, expires_in 3600 i popis dodijeljenih scopeova.
- Token stavite u zaglavlje Authorization: Bearer <access_token> na svakom sljedećem pozivu.
- Što ste zapravo dobili, provjerite s GET /v1/me: tenant, scopeovi i trenutačni bucketi ograničenja.
Svi endpointi
| Metoda | Endpoint | Scope | Idempotency-Key | Zahtjeva / minutu |
|---|---|---|---|---|
| POST | /auth/token Zamjena vjerodajnica za pristupni token | — | — | 120 |
| GET | /me Tenant, scopeovi i trenutačna ograničenja | invoices:read | — | 120 |
Što je 4invoices API
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, odobreni scopeovi i trenutačna ograničenjajavascript
// Spremite token u cache; ne izdavajte novi za svaki zahtjev.
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
Scopeovi
- invoices:read
- invoices:write
- clients:read
- clients:write
- efactura:read
- efactura:submit
Samo server-to-server. Nikada ne zovite API iz JavaScripta u pregledniku: client_secret bi došao do posjetitelja, a CORS ionako blokira svaki origin.
Pogreške
| Status | Tip | Kod |
|---|---|---|
| 401 | authentication_error | invalid_client |
| 401 | authentication_error | token_expired |
| 401 | authentication_error | invalid_token |
| 403 | permission_error | insufficient_scope |
Česte pogreške
- Endpoint za token ima vlastito ograničenje po IP adresi. Jedan token po procesu, obnovljen prije isteka — ne jedan po zahtjevu.
- client_secret pohranjuje se samo kao hash; ako ga izgubite, generirate novu vjerodajnicu i opozovete staru.
- Izdajte zasebne vjerodajnice za ERP, webshop i interne skripte, svaku s minimalnim scopeovima. Opoziv jedne ne utječe na ostale.
- CORS ne dopušta nijedno podrijetlo iz preglednika: API je po dizajnu server-to-server.
Pitanja i odgovori za razvijatelje
Što se događa ako je client_secret pogrešan?
Dobivate 401 s kodom invalid_client. Prekratka tajna pada ranije, već pri validaciji, s 422 validation_failed i param client_secret.
Postoji li zasebno testno okruženje?
Ne. Postoji jedan produkcijski host. Testirajte s predračunima (document_kind proforma) i s /invoices/preview-totals, koji ne troši fiskalni broj.
Mogu li suziti scopeove postojeće vjerodajnice?
Da, iz panela. Već izdani tokeni zadržavaju scopeove s kojima su generirani do isteka, najkasnije za jedan sat.