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

ActionRouteRoles
List license grantsGET /admin/api/v1/license-grantsPLATFORM_ADMIN, BILLING_OPERATOR
Import license grantPOST /admin/api/v1/license-grantsPLATFORM_ADMIN
Import license grant aliasPOST /admin/api/v1/license-grants/importPLATFORM_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

ActionRouteRole
List allocationsGET /api/v1/licenses/allocationsCLIENT_ADMIN, CLIENT_TECH
Create allocationPOST /api/v1/licenses/allocationsCLIENT_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

ActionRouteRole
Usage summaryGET /api/v1/usageCLIENT_ADMIN, CLIENT_TECH, AUDITOR
Billing dashboardGET /api/v1/billing/dashboardCLIENT_ADMIN
Consumption receiptsGET /api/v1/billing/receiptsCLIENT_ADMIN
Monthly reports listGET /api/v1/billing/reportsCLIENT_ADMIN
Monthly report artifactGET /api/v1/billing/reports/{id}/{format}CLIENT_ADMIN
Trigger exportPOST /api/v1/billing/exportCLIENT_ADMIN
Export artifactGET /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:

ActionRouteRole
Tenant dashboardGET /admin/api/v1/billing/dashboard?tenant_id={tenant_id}PLATFORM_ADMIN, BILLING_OPERATOR
Usage summaryGET /admin/api/v1/billing/usage?tenant_id={tenant_id}PLATFORM_ADMIN, BILLING_OPERATOR
Consumption receiptsGET /admin/api/v1/billing/receipts?tenant_id={tenant_id}PLATFORM_ADMIN, BILLING_OPERATOR
Monthly reports listGET /admin/api/v1/billing/reports?tenant_id={tenant_id}PLATFORM_ADMIN, BILLING_OPERATOR
Monthly report artifactGET /admin/api/v1/billing/reports/{id}/{format}?tenant_id={tenant_id}PLATFORM_ADMIN, BILLING_OPERATOR
Trigger exportPOST /admin/api/v1/billing/exportPLATFORM_ADMIN
Export artifactGET /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

FailureBackend behavior
Grant signature fails verification (instance fingerprint, Exaion keyring, or commercial chain)BAD_REQUEST; grant not imported.
Duplicate grant IDCONFLICT; original grant preserved.
Allocation exceeds parent subtree capacityBAD_REQUEST; caller must request capacity from the parent first.
Allocation quota conflict (license type, validity window)BAD_REQUEST.
Admin billing route called without tenant_idBAD_REQUEST.
BILLING_OPERATOR attempts a write (grant import, allocation, export trigger)FORBIDDEN.
Report worker cannot write to S3_BUCKET_EXPORTSJob moves to DLQ; export remains pending.
Requested artifact path escapes tenant/month prefixBAD_REQUEST; no object returned.

Admin Checklist

After importing a grant and allocating licenses:

CheckExpected result
Grant appears in GET /admin/api/v1/license-grantsListed once with expected quantity and dates.
Allocation visible to CLIENT_ADMINGET /api/v1/licenses/allocations returns the new row.
Previously AWAITING_LICENSE proofs can retryStatus transitions out of AWAITING_LICENSE on the next retry cycle.
Audit log entries exist for grant import and allocationEntry hash populated, caller recorded.
Monthly report worker regenerates after allocation changeNext reports.monthly run reflects the new capacity.