Vyměňte client_id a client_secret za Bearer token platný hodinu, pouze server-to-server.
První faktura v 6 krocích
- Vytvořte přihlašovací údaje v panelu v sekci Fakturace → Nastavení → Přístup k API a client_secret ihned zkopírujte — zobrazí se jen jednou.
- Odešlete POST /v1/auth/token s grant_type client_credentials, client_id a client_secret.
- Dostanete access_token, token_type Bearer, expires_in 3600 a seznam udělených scope.
- Token vložte do hlavičky Authorization: Bearer <access_token> u každého dalšího volání.
- Ověřte, co jste skutečně dostali, pomocí GET /v1/me: tenant, scope a aktuální kvóty limitů.
Všechny endpointy
| Metoda | Endpoint | Scope | Idempotency-Key | Požadavků / minutu |
|---|---|---|---|---|
| POST | /auth/token Výměna přihlašovacích údajů za přístupový token | — | — | 120 |
| GET | /me Tenant, scope a aktuální limity | invoices:read | — | 120 |
Co je 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, udělené scope a aktuální skupiny limitůjavascript
// Token ukládejte do cache; nevytvářejte nový u každého požadavku.
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
Pouze server-to-server. Nikdy nevolejte API z JavaScriptu v prohlížeči: client_secret by se dostal k návštěvníkovi a CORS stejně blokuje každý původ.
Chyby
| Stav | Typ | Kód |
|---|---|---|
| 401 | authentication_error | invalid_client |
| 401 | authentication_error | token_expired |
| 401 | authentication_error | invalid_token |
| 403 | permission_error | insufficient_scope |
Časté chyby
- Endpoint tokenů má vlastní limit podle IP. Jeden token na proces, obnovovaný před vypršením — ne jeden na každý požadavek.
- client_secret se ukládá jen jako hash; když ho ztratíte, vytvoříte nové údaje a staré zrušíte.
- Vytvořte samostatné přihlašovací údaje pro ERP, e-shop a interní skripty, každé s minimálními scope. Zrušení jednoho neovlivní ostatní.
- CORS nepovoluje žádný původ z prohlížeče: API je záměrně určeno pro komunikaci mezi servery.
Otázky a odpovědi pro vývojáře
Co se stane, když je client_secret špatný?
Dostanete 401 s kódem invalid_client. Příliš krátký secret selže dříve, už při validaci, s 422 validation_failed a param client_secret.
Existuje samostatný sandbox?
Ne. Existuje jeden produkční host. Testujte pomocí proforma (document_kind proforma) a pomocí /invoices/preview-totals, který nespotřebuje žádné fiskální číslo.
Mohu zúžit scope existujících přihlašovacích údajů?
Ano, z panelu. Tokeny, které už byly vydány, si ponechají scope, se kterými vznikly, až do vypršení, tedy nejvýše hodinu.