Guides

Authentication

The API supports two authentication methods: API keys for direct integrations with a single company, and OAuth 2.0 for approved partner applications that act on behalf of Talero customers. Both are server-side only — never embed credentials in a browser or mobile app.

API keys

A company owner creates API keys in Talero under Indstillinger → API-nøgler (Settings → API keys). Scopes are chosen at creation time and cannot be broadened afterwards — create a new key instead. The full key is shown exactly once.

Keys have the format tlr_live_ followed by 48 hex characters and are sent in the X-API-Key header:

curl https://app.talero.dk/api/v1/invoices \
  -H "X-API-Key: tlr_live_4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e"

Treat API keys like passwords: store them in a server-side secret manager, never commit them to source control, and rotate them by creating a replacement key and revoking the old one.

Scopes

Each API key and OAuth grant carries an explicit list of scopes. Requests to an endpoint outside the granted scopes fail with 403 forbidden. There are 17 scopes:

ScopeGrants
invoices:read / invoices:writeRead and manage invoices
customers:read / customers:writeRead and manage customers
products:read / products:writeRead and manage products
expenses:read / expenses:writeRead and manage expenses
accounts:read / accounts:writeRead and manage the chart of accounts
transactions:read / transactions:writeRead and post ledger transactions
suppliers:read / suppliers:writeRead and manage suppliers
reports:readRead financial reports
exports:readGenerate SAF-T exports
webhooks:manageManage webhook subscriptions, deliveries, replay and secret rotation

Request the minimum set of scopes your integration needs.

OAuth 2.0 for partner applications

Partner applications use the OAuth 2.0 Authorization Code flow with PKCE (RFC 7636, S256 — mandatory). Only confidential clients are supported: your application must be able to keep a client_secret on a server.

1. Register a client

Client registration is a manual process. Email [email protected] with your application name, a technical contact, the exact HTTPS redirect URIs and the scopes you need. Talero provisions a confidential client and shares the client_id and client_secret (the secret is shown once).

2. Generate a PKCE verifier and challenge

For every authorization request, generate a fresh high-entropy code_verifier and derive the code_challenge as the base64url-encoded (unpadded) SHA-256 hash of the verifier:

Node.js
const crypto = require('crypto');

const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto
  .createHash('sha256')
  .update(codeVerifier)
  .digest('base64url');
Shell (OpenSSL)
code_verifier=$(openssl rand -base64 48 | tr '+/' '-_' | tr -d '=')
code_challenge=$(printf '%s' "$code_verifier" \
  | openssl dgst -sha256 -binary \
  | openssl base64 -A | tr '+/' '-_' | tr -d '=')

Store the code_verifier server-side (bound to the pending authorization via state) — you need it in step 4.

3. Send the user to the authorization page

Redirect the user's browser to the authorization URL. The user logs in to Talero, selects which of their companies the application may access, and approves the requested scopes.

https://app.talero.dk/oauth/authorize
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
  &state=af0ifjsldkj
  &scope=invoices%3Aread%20customers%3Aread
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
ParameterDescription
client_idYour client identifier.
redirect_uriOne of the exact HTTPS redirect URIs registered for the client.
stateOpaque CSRF token. Verify it on the callback before exchanging the code.
scopeSpace-separated scopes, a subset of what the client was registered with.
code_challengeBase64url (unpadded) SHA-256 of the code_verifier.
code_challenge_methodMust be S256. The plain method is not supported.

On approval, Talero redirects back to your redirect_uri with code and state query parameters. Authorization codes are single-use and short-lived.

4. Exchange the code for tokens

From your server, call the token endpoint with a JSON body containing the code, your client credentials and the PKCE verifier:

curl -X POST https://app.talero.dk/api/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "tlr_code_...",
    "redirect_uri": "https://example.com/callback",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
  }'
Response — 200 OK
{
  "access_token": "tlr_at_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "tlr_rt_...",
  "scope": "invoices:read customers:read"
}

5. Call the API

Send the access token as a Bearer token. OAuth-authenticated requests use the same endpoints, envelopes and rate limits as API keys.

curl https://app.talero.dk/api/v1/customers \
  -H "Authorization: Bearer tlr_at_..."

6. Refresh tokens

Access tokens expire after one hour. Use the refresh token to obtain a new pair:

curl -X POST https://app.talero.dk/api/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "tlr_rt_...",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'

Refresh tokens are single-use: each refresh returns a new refresh token and invalidates the old one. If a previously used refresh token is replayed, Talero treats it as a possible theft and revokes the entire token family — the user must re-authorize. Persist the newest refresh token atomically before discarding the old one.

7. Revoke tokens

Revoke a token you no longer need (RFC 7009), for example when a user disconnects your application:

curl -X POST https://app.talero.dk/api/oauth/revoke \
  -H "Content-Type: application/json" \
  -d '{
    "token": "tlr_rt_...",
    "token_type_hint": "refresh_token",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'

Token lifetimes

CredentialFormatLifetime
API keytlr_live_ + 48 hex charsUntil revoked (optional expiry at creation)
Access tokentlr_at_...1 hour
Refresh tokentlr_rt_...30 days, single-use with rotation

The OAuth token endpoint is rate limited separately from the API: 10 requests per 60 seconds per client and IP address. See Rate limits.