Skip to content

Authentication

Every request to /api/v1/* must carry a bearer token:

Authorization: Bearer <token>
Accept: application/json

There are two ways to get one, for two different use cases.

Organization API tokens (server-to-server)

The simplest path for integrations: create a token in the admin panel under Organization → API Tokens.

  • The token is shown once at creation — store it securely.
  • It is bound to one organization; you don't need to select an organization per request, but if you send X-Organization-Id it must match the token's organization.
  • Each token has its own scopes (see below; * grants all).
  • Tokens can be given an expiry date, and are revoked from the same admin page (not via the logout endpoint).

OAuth 2.0 Authorization Code + PKCE (apps acting for users)

For applications where a user signs in with their own EncryptInvoice account, use the standard OAuth 2.0 Authorization Code flow with PKCE. It is a public client flow — there is no client secret.

  1. Generate a code_verifier (random 43–128 chars) and its code_challenge (Base64url(SHA-256(verifier))), plus a random state.
  2. Open the system browser at:
GET /oauth/authorize
    ?client_id=<client_id>
    &redirect_uri=<registered redirect URI>
    &response_type=code
    &scope=<space-separated scopes>
    &state=<state>
    &code_challenge=<code_challenge>
    &code_challenge_method=S256
  1. After sign-in, the browser is redirected to your redirect_uri with ?code=...&state=.... Verify state, then exchange the code:
POST /oauth/token
grant_type=authorization_code
client_id=<client_id>
redirect_uri=<same redirect URI>
code=<code>
code_verifier=<original verifier>

Response:

{
  "token_type": "Bearer",
  "expires_in": 1296000,
  "access_token": "eyJ0eXAiOiJKV1Q...",
  "refresh_token": "def50200..."
}

Refreshing

POST /oauth/token
grant_type=refresh_token
refresh_token=<refresh_token>
client_id=<client_id>

Refresh rotation is on: each refresh returns a new access and refresh token and revokes the old refresh token. Replace the stored pair atomically; a 400 invalid_grant means the session has ended — restart the sign-in flow.

Signing out

Endpoint Effect
POST /api/v1/logout Revokes the token used on this request (and its refresh token).
POST /api/v1/logout-all Revokes all of the user's API tokens on every device.

Revocation is immediate. Organization API tokens are managed in the admin panel and return 400 invalid_token_type on these endpoints.

Scopes

Scope Grants
organizations:read List/read organizations
invoices:read / invoices:write / invoices:send / invoices:delete Invoices
quotes:read / quotes:write / quotes:convert Quotes
customers:read / customers:write Customers
contacts:read / contacts:write Contacts
expenses:read / expenses:write Expenses
einvoicing:send / einvoicing:participants E-invoicing submission and participant lookup

Scopes declare your app's intent; actual authorization is additionally enforced per user and role on every request. A token can never do more than the user or organization behind it is allowed to.

Token lifetimes

Credential Lifetime
OAuth access token 15 days
OAuth refresh token 30 days (rotated on each refresh)
Organization API token Optional expiry (never, if not set)

We use cookies and privacy-respecting analytics

We use essential cookies for authentication and privacy-respecting analytics (self-hosted, respects Do Not Track). No advertising or third-party tracking. Learn more in our Privacy Policy