Licensing
DocAI Fabric meters imported pages against your license volume and periodically syncs with a License Server. The License page (open the user menu at the bottom of the sidebar and choose License under the current tenant; requires the Manage license permission, held by Administrators by default) shows everything about this: your license, consumption against it, sync status, and, verbatim, the exact data exchanged with the License Server.
How it works
- Your license grants a page volume, either a recurring allowance (for example 10,000 pages per month) or an absolute total. Volume is counted in imported pages; nothing else is metered against the license. See What counts against your volume below.
- The deployment keeps a locally cached, signed license snapshot and decides admission locally: there is no per-request call to the License Server. When the license has expired or the volume (plus any agreed overage) is used up, you can still create transactions and upload files, but the page-import step fails with the reason recorded in the transaction's activity log. Once the license is usable again, re-run the affected transactions from the beginning.
- A background sync runs roughly every 15 minutes: it reports cumulative page counters and receives a fresh snapshot. If the License Server is unreachable, processing continues under the license's offline policy (either indefinitely, or for a configured grace period). The Sync now button on the License page triggers one immediate round trip.
What counts against your volume
The meter is imported pages: the pages of the documents you feed in. Every page you import counts, once. Nothing else is metered, not the number of transactions, documents or fields, not exports, and not the AI calls behind classification and extraction.
A page counts once, when its content is first imported. Processing the same pages again is free. Concretely:
| What you do | Counts against volume? |
|---|---|
| Upload files and process them | Yes, every page |
| Re-run a transaction from the beginning | No |
| Re-run one step, or re-run from a checkpoint | No |
| Re-process a document, or re-extract its fields | No |
| Copy a transaction to another dataset and run it there | No |
| Export, re-export, or export in another format | No |
| Add another file to a transaction and import it | Yes, the added file's pages |
| Replace a file with a different one and import it | Yes, the replacement's pages |
| Import the same document again as a new transaction | Yes, it is a new import |
Why re-runs are free. Re-running is nearly always configuration work or problem mitigation rather than new volume: you are tuning a prompt, fixing a splitting rule, testing a change in the playground, or recovering from a failed step. Charging for that would put a price on getting your setup right, and would make people hesitate before the retry that fixes their data. So the meter follows the documents you bring in, not the number of times the system looks at them.
What "the same content" means. Sameness is decided by the file contents, not by the file name or the page count. Replacing a 10-page file with a different 10-page file under the same name is a new import and is metered, because the content is different. Re-importing the identical file, under any name, is not.
Volume is per organisation. Each tenant has its own allowance. If a transaction is brought into a different organisation's workspace (for example by importing a shared project), its pages are metered there on first import, because that organisation has its own license.
Network requirements (firewall setup)
For self-hosted deployments, licensing needs exactly one firewall rule: outbound HTTPS to the License Server. The License Server never connects to your deployment: no inbound rule, port forwarding or VPN is required.
| Parameter | Value |
|---|---|
| Destination host | license.docaifabric.com (the host actually configured for your deployment is shown on the License page under License Server sync → Server) |
| Protocol | HTTPS (TLS) |
| Port | TCP 443 |
| Direction | Outbound only, always initiated by your deployment |
| Frequency | Every 15 minutes by default; every minute when the volume pool is nearly exhausted; after a failure, retries with 1-15 minute backoff |
| DNS | The host is resolved by name and its IP address can change, so use an FQDN-based firewall rule, not an IP allowlist, and allow DNS resolution for the host |
┌───────────────────────────────┐ ┌──────────────────────────┐
│ Your network (self-hosted) │ │ Internet │
│ │ │ │
│ ┌─────────────────────────┐ │ outbound HTTPS │ ┌────────────────────┐ │
│ │ DocAI Fabric container │ │ TCP 443 │ │ License Server │ │
│ │ (background sync loop) ├──┼─────────────────▶│ │ license │ │
│ └─────────────────────────┘ │ every ~15 min │ │ .docaifabric.com │ │
│ │ │ └────────────────────┘ │
│ no inbound connections │ ◀────✕──── │ │
└───────────────────────────────┘ └──────────────────────────┘
All requests go to paths under the destination host:
| Endpoint | When it is called |
|---|---|
POST /v1/registrations | Once per tenant, on first start |
POST /v1/environments/{environment_id}/sync | Every periodic sync, and on Sync now |
GET /v1/server-public-key | Once on first contact, only for trust-on-first-use deployments (skipped when the server key is pinned) |
Two things to watch for in restrictive networks:
- The deployment makes a direct HTTPS connection; it does not route licensing traffic through an HTTP proxy.
- If your firewall performs TLS inspection (HTTPS interception), exempt
license.docaifabric.comfrom it, or make sure the inspecting proxy's CA certificate is trusted inside the container; otherwise certificate verification fails and syncs are rejected.
If the connection is blocked, nothing stops immediately: processing continues under the license's offline policy (see When limits are hit), and the License page shows the last successful sync so you can verify the rule works: press Sync now after changing firewall settings to test the connection on the spot.
What the License page shows
| Section | Meaning |
|---|---|
| Status banner | Whether new page imports are currently admitted, and why not if they aren't. |
| License | Volume, period, expiry, what happens when the volume is reached, offline policy. |
| Consumption | Pages confirmed by the License Server for the current period, plus pages imported locally since the last sync: together, your honest position against the volume. |
| License Server sync | When the last sync happened, how often it refreshes, how many reports have been sent. |
| Identity & signatures | The signing keys involved (see below). |
| What leaves this system | The verbatim last payloads sent and received. |
Where else the license shows
- Monitoring carries a License card with a traffic light, the pages left and the day they run out, for everyone who watches production.
- The user menu (bottom of the sidebar) shows a License row under the current tenant to holders of the Manage license permission, with the same state, and opens this page.
Both read the same status as the notification emails, so a licence that needs attention looks the same everywhere.
What leaves your system
Every exchange with the License Server is a plain, readable JSON payload beside a detached Ed25519 signature, and nothing is encrypted away or encoded out of sight:
{
"payload": { "...plain readable JSON..." : "..." },
"sig": { "alg": "Ed25519", "key_id": "k-…", "signature": "base64…" }
}
Payloads sent by your deployment may contain only the following (this is a closed list, enforced by schema):
- Identifiers:
deployment_id,environment_id,tenant_id,license_id,report_seq - Deployment metadata:
app_url,product_version, the deployment's public signing key - Timestamps:
window_end,period_start - Counters:
import_pages,import_documents,import_files,import_transactions,export_pages - Optionally the tenant's display name (
tenant_name), the only quasi-identifying field; it can be left out for privacy-sensitive deployments.
Document content, file names, extracted field values, user names, e-mail addresses and IP addresses never appear in any payload.
Sent: usage report
{
"payload": {
"report_seq": 12,
"environment_id": "env-…",
"license_id": "lic-…",
"period_start": "2026-06-01",
"cumulative": {
"import_pages": 1240,
"import_documents": 310,
"import_files": 270,
"import_transactions": 255,
"export_pages": 980
},
"window_end": "2026-06-11T12:00:00Z"
},
"sig": { "alg": "Ed25519", "key_id": "k-…", "signature": "…" }
}
Counters are cumulative since the start of the current period, so a re-sent report can never double-count: the server keeps the maximum it has seen.
Received: license snapshot
The snapshot describes what you are licensed for and the server-confirmed pool state: license id, volume, period, expiry, overage allowance, offline policy, and pages consumed/remaining. It is signed by the License Server; your deployment refuses snapshots that do not verify.
Signatures and keys
- Your deployment generates its own Ed25519 keypair on first registration and signs everything it sends, so the License Server can attribute every report, and you get non-repudiation of exactly what was reported.
- License snapshots are signed by the License Server. The server's public key is either pinned in your deployment configuration (shown as pinned on the License page) or fetched once on first contact (trust-on-first-use).
When limits are hit
Hitting a limit never blocks you out of the application: you can still log in, create transactions, upload files, review, and export. What stops is the page-import step, the metered operation. A transaction whose import is blocked fails immediately, with the license reason (expired, volume exhausted, …) recorded in its activity log, so stuck work is always visible and explained. Transactions already past import finish normally.
| Situation | Behaviour |
|---|---|
| Volume (plus any agreed overage) used up | Imports of new content fail until the next period starts or the license is upgraded. Re-running transactions whose pages were already counted still works. |
| License expired | Imports of new content fail until the license is renewed. Re-running already-counted transactions still works. |
| License Server unreachable | Nothing stops immediately. With a fail-open policy processing continues indefinitely; with fail-closed, it continues for the configured grace period, and then new page imports fail until a sync succeeds. |
To recover, fix the license (renew, upgrade, or restore connectivity; the status banner on the License page tells you which), then re-run the failed transactions from the beginning; nothing needs to be re-uploaded.
Transaction creation and processing calls are accepted even while the license is blocked; the transaction then fails at its import step. Poll the transaction status as usual; a license failure appears as a failed transaction whose error names the license reason. Re-running it after the license is restored uses the standard re-run endpoint.
Email notifications
The deployment can warn tenant admins before a limit is hit, by email:
- Upcoming expiration: from 3 weeks out (21 / 14 / 7 / 3 / 2 / 1 days and on expiry).
- Volume consumption: at 80 / 90 / 95 / 100% of the period's volume. The email states what happens at the volume: hard stop, an agreed overage, or nothing (for licenses that never stop on volume).
- Lost License Server connection: a countdown to the offline grace deadline (24 / 12 / 6 / 3 / 2 / 1 hours and when it elapses). Sent for fail-open licenses too, as a heads-up that processing continues.
By default the recipients are all tenant admins; the Email notifications section of the License page lets you disable that, add extra addresses, or turn notifications off entirely. Sending requires the deployment to have email (SMTP) configured; the License page warns if it doesn't.
If a threshold is crossed while the system is down or unreachable, the next sync evaluates the ladders again; each threshold fires at most once per license period or expiry date, and re-arms automatically on renewal or when a new period starts.