Licenses And Billing
Import license grants, allocate licenses, trigger billing exports, and retrieve report artifacts.
Licenses And Billing
License grants are platform-admin managed. Tenant billing exports are available to tenant admins, and restricted tenant-selected billing views are available to platform admins and billing operators.
License Grants
| Action | Route | Roles |
|---|---|---|
| List license grants | GET /admin/api/v1/license-grants | PLATFORM_ADMIN, BILLING_OPERATOR |
| Import license grant | POST /admin/api/v1/license-grants | PLATFORM_ADMIN |
| Import license grant alias | POST /admin/api/v1/license-grants/import | PLATFORM_ADMIN |
Example import:
{
"tenant_id": "11111111-1111-4111-8111-111111111111",
"grant_id": "55555555-5555-4555-8555-555555555555",
"grant_type": "QUANTITY",
"instance_fingerprint": "sha256:example",
"license_type": "desktop",
"quantity": 100,
"valid_from": "2026-01-01",
"valid_until": "2026-12-31",
"commercial_chain": ["Exaion", "Example Operator"],
"signature": "dev-signature"
}
Imports validate the signed instance fingerprint against the tenant, reject duplicate grants globally, validate addendum and revocation chains, and require the commercial chain to start with Exaion and end with the current operator. The final production Exaion keyring/rotation policy remains part of the signer readiness backlog.
License Allocations
| Action | Route | Role |
|---|---|---|
| List allocations | GET /api/v1/licenses/allocations | CLIENT_ADMIN, CLIENT_TECH |
| Create allocation | POST /api/v1/licenses/allocations | CLIENT_ADMIN |
Create allocation:
{
"organization_id": "22222222-2222-4222-8222-222222222222",
"grant_id": "55555555-5555-4555-8555-555555555555",
"license_type": "desktop",
"quantity": 10
}
Allocation enforces tenant scope, caller organization subtree, grant license type, parent allocation capacity, and user quotas where configured.
Billing And Reports
| Action | Route | Role |
|---|---|---|
| Usage summary | GET /api/v1/usage | CLIENT_ADMIN, CLIENT_TECH, AUDITOR |
| Billing dashboard | GET /api/v1/billing/dashboard | CLIENT_ADMIN |
| Consumption receipts | GET /api/v1/billing/receipts | CLIENT_ADMIN |
| Monthly reports list | GET /api/v1/billing/reports | CLIENT_ADMIN |
| Monthly report artifact | GET /api/v1/billing/reports/{id}/{format} | CLIENT_ADMIN |
| Trigger export | POST /api/v1/billing/export | CLIENT_ADMIN |
| Export artifact | GET /api/v1/billing/export/{id}/{format} | CLIENT_ADMIN |
Admin billing routes require an explicit target tenant and never expose certificate PDFs, canonical proof JSON, or proof payload content:
| Action | Route | Role |
|---|---|---|
| Tenant dashboard | GET /admin/api/v1/billing/dashboard?tenant_id={tenant_id} | PLATFORM_ADMIN, BILLING_OPERATOR |
| Usage summary | GET /admin/api/v1/billing/usage?tenant_id={tenant_id} | PLATFORM_ADMIN, BILLING_OPERATOR |
| Consumption receipts | GET /admin/api/v1/billing/receipts?tenant_id={tenant_id} | PLATFORM_ADMIN, BILLING_OPERATOR |
| Monthly reports list | GET /admin/api/v1/billing/reports?tenant_id={tenant_id} | PLATFORM_ADMIN, BILLING_OPERATOR |
| Monthly report artifact | GET /admin/api/v1/billing/reports/{id}/{format}?tenant_id={tenant_id} | PLATFORM_ADMIN, BILLING_OPERATOR |
| Trigger export | POST /admin/api/v1/billing/export | PLATFORM_ADMIN |
| Export artifact | GET /admin/api/v1/billing/export/{id}/{format}?tenant_id={tenant_id} | PLATFORM_ADMIN, BILLING_OPERATOR |
Supported export formats:
csv, xlsx, json, pdf
Example export:
{
"tenant_id": "11111111-1111-4111-8111-111111111111",
"report_type": "monthly",
"formats": ["csv", "xlsx", "json", "pdf"],
"delivery": {
"email": true,
"s3_drop": {
"enabled": true,
"target": "s3://billing-drop/example-prefix"
}
}
}
Report Artifacts
The report worker writes deterministic sibling artifacts under:
tenant/{tenant_id}/exports/monthly/{YYYY-MM}.{json,csv,xlsx,pdf}
Download routes validate that stored object keys stay under the expected tenant/month prefix before serving artifacts.
Retention
The maintenance worker applies audit and public verification retention. Monthly report artifact pruning is exposed as a backend hook and should be wired to the production scheduler with the selected retention period.
Billing Operator Boundary
BILLING_OPERATOR is read-only. It can list grants, read restricted admin
billing views, download existing reports/exports, and inspect audit or
verification logs. It cannot import grants, allocate licenses, change tenants,
or trigger a new billing export.
Failure Semantics
| Failure | Backend behavior |
|---|---|
| Grant signature fails verification (instance fingerprint, Exaion keyring, or commercial chain) | BAD_REQUEST; grant not imported. |
| Duplicate grant ID | CONFLICT; original grant preserved. |
| Allocation exceeds parent subtree capacity | BAD_REQUEST; caller must request capacity from the parent first. |
| Allocation quota conflict (license type, validity window) | BAD_REQUEST. |
Admin billing route called without tenant_id | BAD_REQUEST. |
BILLING_OPERATOR attempts a write (grant import, allocation, export trigger) | FORBIDDEN. |
Report worker cannot write to S3_BUCKET_EXPORTS | Job moves to DLQ; export remains pending. |
| Requested artifact path escapes tenant/month prefix | BAD_REQUEST; no object returned. |
Admin Checklist
After importing a grant and allocating licenses:
| Check | Expected result |
|---|---|
Grant appears in GET /admin/api/v1/license-grants | Listed once with expected quantity and dates. |
Allocation visible to CLIENT_ADMIN | GET /api/v1/licenses/allocations returns the new row. |
Previously AWAITING_LICENSE proofs can retry | Status transitions out of AWAITING_LICENSE on the next retry cycle. |
| Audit log entries exist for grant import and allocation | Entry hash populated, caller recorded. |
| Monthly report worker regenerates after allocation change | Next reports.monthly run reflects the new capacity. |