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:
| Scope | Grants |
|---|---|
invoices:read / invoices:write | Read and manage invoices |
customers:read / customers:write | Read and manage customers |
products:read / products:write | Read and manage products |
expenses:read / expenses:write | Read and manage expenses |
accounts:read / accounts:write | Read and manage the chart of accounts |
transactions:read / transactions:write | Read and post ledger transactions |
suppliers:read / suppliers:write | Read and manage suppliers |
reports:read | Read financial reports |
exports:read | Generate SAF-T exports |
webhooks:manage | Manage 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:
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
| Parameter | Description |
|---|---|
client_id | Your client identifier. |
redirect_uri | One of the exact HTTPS redirect URIs registered for the client. |
state | Opaque CSRF token. Verify it on the callback before exchanging the code. |
scope | Space-separated scopes, a subset of what the client was registered with. |
code_challenge | Base64url (unpadded) SHA-256 of the code_verifier. |
code_challenge_method | Must 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
| Credential | Format | Lifetime |
|---|---|---|
| API key | tlr_live_ + 48 hex chars | Until revoked (optional expiry at creation) |
| Access token | tlr_at_... | 1 hour |
| Refresh token | tlr_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.