SAPI-SK: authentication (OAuth2)
SAPI-SK uses the OAuth 2.0 client_credentials grant. In exchange for a client ID and secret you get a short-lived access token (JWT, 15 minutes) and a long-lived refresh token (30 days) to renew it without resending the secret.
Getting tokens
You create the client ID and secret in the partner developer portal (developers.efaktura.sk → Dashboard → SAPI-SK, path /dashboard/sapi). The secret is shown only once. Exchange them for a token pair:
X-API-Key), not SAPI-SK credentials. Access to the developer portal is invite-only: write to podpora@efaktura.sk and we will send you an invitation. A test (sandbox) client is available immediately and free of charge; the live client is activated once partner access is approved.POST https://api.efaktura.sk/sapi/auth/token
Content-Type: application/json
{
"client_id": "sapi_live_xxxxxxxxxxxx",
"client_secret": "••••••••••••••••••••",
"grant_type": "client_credentials",
"scope": "document:send document:receive"
}Response (200):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900,
"scope": "document:send document:receive",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_expires_in": 2592000
}refresh_token and refresh_expires_in fields are our own extension. The original SAPI schema forgot to declare them in the response, even though the /auth/renew endpoint requires a refresh token, so we return them.Using the access token
Send the access token in the Authorization: Bearer <access_token> header on all document calls, together with the X-Peppol-Participant-Id header.
Checking token status
Before renewing, you can check how much time is left on the token. If should_refresh is true (less than 3 minutes to expiry), proactively refresh the token.
GET https://api.efaktura.sk/sapi/auth/token/status
Authorization: Bearer <access_token>
// 200
{
"valid": true,
"token_type": "access",
"client_id": "sapi_live_xxxxxxxxxxxx",
"issued_at": "2026-07-04T10:00:00.000Z",
"expires_at": "2026-07-04T10:15:00.000Z",
"expires_in_seconds": 542,
"should_refresh": false,
"refresh_recommended_at": "2026-07-04T10:12:00.000Z"
}Renewing tokens (rotation)
You exchange a refresh token for a new pair. This is a rotation: the original refresh token is invalidated and you receive a new one. Always store the new pair from the response.
POST https://api.efaktura.sk/sapi/auth/renew
Content-Type: application/json
{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
// 200: same shape as /auth/token (a new access and a new refresh token)/auth/token.Invalidation (revoke)
On logout, or if you suspect a refresh token leaked, revoke it. The operation is idempotent: it always returns success (even for an unknown token, per RFC 7009).
POST https://api.efaktura.sk/sapi/auth/revoke
Content-Type: application/json
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type_hint": "refresh_token" }
// 200
{ "success": true, "message": "Token revoked successfully", "timestamp": "2026-07-04T10:20:00.000Z" }Brute-force protection (lockout)
After 5 failed token attempts for a given client_id, the client is temporarily locked for 15 minutes: further calls return 423 (SAPI-AUTH-005). A successful authentication resets the counter.
IP allowlist
You can optionally set an allowed IP address list for a client. If it's set and a token request arrives from a different IP, 403 is returned (SAPI-AUTH-004).