Authentication
How to authenticate requests to the Beliq API using API keys.
All /v1/* endpoints require an API key. If a key is missing, the API returns 401 AUTHENTICATION_REQUIRED.
Obtaining an API key
- Sign in to the Beliq dashboard
- Navigate to Integration → API Keys
- Click Create API Key and give it a descriptive label
- Copy the key immediately — it is only displayed once
API keys are stored securely in hashed form. Beliq does not store or log your plaintext key.
Passing the API key
Use one of two methods:
Authorization header (recommended)
Authorization: Bearer YOUR_API_KEYimport { Beliq } from '@beliq/sdk';
// `auth: 'bearer'` sends Authorization: Bearer instead of the default X-API-Key.
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY!, auth: 'bearer' });import os
from beliq import Beliq
# auth="bearer" sends Authorization: Bearer instead of the default X-API-Key.
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"], auth="bearer")X-API-Key header
X-API-Key: YOUR_API_KEYimport { Beliq } from '@beliq/sdk';
// X-API-Key is what the client sends unless you ask for `auth: 'bearer'`.
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });import os
from beliq import Beliq
# X-API-Key is what the client sends unless you ask for auth="bearer".
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])Both methods work the same way. Use whichever is easier in your client.
Example request
curl -X POST https://api.beliq.eu/v1/validate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/xml" \
--data-binary @invoice.xmlimport { readFile } from 'node:fs/promises';
import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const result = await beliq.validate(await readFile('invoice.xml'));
console.log(result.valid, result.format, result.schematronVersion);import os
from pathlib import Path
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
result = beliq.validate(Path("invoice.xml").read_bytes())
print(result.valid, result.format, result.schematron_version)Verifying a key
GET /v1/me returns the account, plan, and live allowance for the calling key. It is a lightweight credential check that does not count against your monthly quota, so it is the right call for “is this key valid?” probes. The official connectors and SDKs use it to validate stored credentials.
curl https://api.beliq.eu/v1/me \
-H "Authorization: Bearer YOUR_API_KEY"import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
// `me()` is the credential check: it does not draw on your monthly quota.
const account = await beliq.me();
console.log(account.livemode, account.plan.name, account.quota.remaining);import os
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
# me() is the credential check: it does not draw on your monthly quota.
account = beliq.me()
print(account.livemode, account.plan.name, account.quota.remaining){
"success": true,
"data": {
"keyId": "3f9c2a1b-8e4d-4c7a-9b21-5e0f7d8a6c31",
"keyPrefix": "blq_live",
"livemode": true,
"org": {
"id": "7b2e9d14-6a03-4f58-8c9e-2d1b4a7f0e63",
"name": "Acme AG",
"rulesetChannel": "latest"
},
"plan": { "id": 3, "name": "Growth" },
"rateLimitPerMinute": 200,
"quota": { "limit": 10000, "used": 1234, "remaining": 8766, "resetsAt": "2026-07-20T09:00:00.000Z" }
}
}quota describes the allowance the calling key spends, and livemode says which one that is. On a live key it is your plan quota, and resetsAt is the end of the current window: one month anchored on your billing day, so it falls on the 1st only if your subscription renews on the 1st. On a test key it is the sandbox allowance instead, on the UTC calendar month. Read resetsAt rather than assuming a month boundary. See test mode for what a blq_test_ key reads back.
keyPrefix is the first eight characters of the key, so it reads blq_live or blq_test and carries no key material: only a hash of the key itself is stored. keyId and the org id are UUIDs.
plan.name is never null. An account on the free tier references no plan record, so plan.id is null while plan.name is the free tier’s name. A 401 or 403 here means the key is missing, malformed, or revoked (see the table below).
Error responses
| HTTP Status | Error Code | Meaning |
|---|---|---|
| 401 | AUTHENTICATION_REQUIRED |
No API key was provided, or the key format is invalid |
| 403 | INVALID_API_KEY |
The API key does not exist or has been revoked |
| 429 | QUOTA_EXCEEDED |
Your monthly usage quota is exhausted — upgrade your plan |
| 429 | RATE_LIMITED |
Too many requests in the current rate-limit window — back off and retry |
Quotas and rate limits
Beliq applies request limits to keep the service reliable and fair for all customers.
| Throttle | Window | Source of truth | 429 error code |
|---|---|---|---|
| Monthly quota | One month anchored on your billing day | subscriptionPlans.monthlyQuota (per plan) |
QUOTA_EXCEEDED |
| Sandbox allowance (test keys) | Calendar month (UTC) | Flat, independent of plan | QUOTA_EXCEEDED |
| Per-minute burst | Rolling 1-minute window | Plan-based rate limit | RATE_LIMITED |
| Abuse throttle | Temporary protection window | Beliq runtime | ACCOUNT_THROTTLED |
The two monthly windows do not line up: only an account billed on the 1st sees its plan quota reset when the sandbox allowance does. GET /v1/me reports the boundary that applies to the calling key.
Quota and rate limits are tracked per account. All API keys belonging to the same account share the same quota and burst limit.
Burst and sustained throughput
The per-minute figure is a burst allowance, not a sustained rate. You may spend the whole minute’s allowance at once, and Beliq queues what it cannot start immediately rather than rejecting it. Your sustained throughput is governed by your monthly quota.
The two are deliberately far apart, so it is worth being concrete: a Business plan allows 300 requests per minute against a quota of 20,000 documents per month. Sending 300 every minute would exhaust the month’s quota in about 67 minutes. Size your integration against the quota, and treat the per-minute figure as headroom for batches and spikes.
A queued request answers more slowly, which is normal and not an error. If a burst is large enough that Beliq cannot serve it inside the request deadline, you get a 503 with Retry-After and the document’s quota unit is not consumed, so retrying is free.
Plan changes mid-window: an upgrade raises the cap on your current window immediately, so the allowance you just paid for is usable the moment the payment lands. A downgrade does not shrink it: the current window keeps the allowance it was billed at, and the smaller one applies from the next window.
QUOTA_EXCEEDED includes your current usage in the message (for example "Monthly quota exceeded (1000/1000)"). Check usage in the dashboard or upgrade your plan.
Response headers
| Header | Set on | Meaning |
|---|---|---|
x-ratelimit-limit |
All /v1/* responses |
Your plan’s request limit for the current minute |
x-ratelimit-remaining |
All /v1/* responses |
Burst budget left in the current minute |
x-ratelimit-reset |
All /v1/* responses |
Seconds until the burst window resets |
Retry-After |
All /v1/* 429 responses |
Seconds to wait before retrying. For RATE_LIMITED this is the seconds left in the burst window; for ACCOUNT_THROTTLED the seconds left in the throttle window, which can be several minutes; for QUOTA_EXCEEDED the seconds until your quota window rolls over (the same instant /v1/me reports as resetsAt), or until the next UTC calendar month for a test-mode key |
Always honor Retry-After when present. It indicates the earliest safe retry time.
Prometheus metrics (operators)
When enabled for your deployment, GET /metrics may include a counter beliq_api_http_429_total labeled by throttle subtype (rate_limit_hit, quota_exhausted, abuse_throttle_hit, unknown), and a histogram beliq_api_http_request_duration_seconds (method, route) for request latency — useful for alerting and SLO dashboards.
Beliq also sends common browser hardening headers (for example X-Content-Type-Options, X-Frame-Options) on API responses; they do not replace your own security review for embedded contexts.
Default per-minute limits by plan
These are the default per-minute burst allowances by plan, alongside the sustained rate each plan’s monthly quota works out to.
| Plan | Burst (requests/minute) | Monthly quota | Sustained average |
|---|---|---|---|
| Free | 10 | 20 | under 1/hour |
| Starter | 100 | 2,000 | ~3/hour |
| Growth | 200 | 10,000 | ~14/hour |
| Business | 300 | 20,000 | ~28/hour |
| Scale | 500 | 50,000 | ~69/hour |
See pricing for what each plan costs.
Test mode uses its own, lower burst allowance. Keys prefixed blq_test_ are limited to 30 requests per minute regardless of plan, with a separate monthly allowance. See test mode.
Key management
- Revoke a key at any time from the dashboard. Revoked keys return
INVALID_API_KEYimmediately. - Rotate keys by creating a new key, updating your integration, then revoking the old key.
- Multiple keys are supported — use separate keys for different environments or services.