Licensing#
Licence status, telemetry preview, activation, renewal, and offline licence install.
5 operations. Roles, error format and pagination are common to the whole API — see the REST API overview.
Authentication
Use a named bearer token. Every endpoint except POST /api/v1/auth/login,
POST /api/v1/auth/enrol and GET /api/v1/system/health requires one. A super-user creates a
token with POST /api/v1/auth/tokens; the plaintext (bngtok_…) is returned exactly once at
creation and only a SHA-256 hash is stored on the appliance, so a lost token is replaced rather
than recovered. Send it on every request:
Each token carries a fixed role (read-only, operator or super-user) and is exempt from CSRF
checks. This is the single credential you need for scripts, integrations and monitoring.
Accounts and tokens share one identity model with the appliance CLI (login.users). Repeated
authentication failures lock the account/source-IP pair out temporarily (HTTP 423 on login).
Session cookies (bundled web UI only)
The appliance also accepts an interactive session cookie, which is how the bundled web UI authenticates. It is documented for completeness — API clients should not use it. It is bound to a login session and obliges the caller to manage a CSRF token, neither of which suits automation.
POST /api/v1/auth/login with username + password (and a TOTP code when enrolled) sets the
bng_session cookie and returns a csrfToken (also available from GET /api/v1/auth/whoami).
Cookie-authenticated mutating requests (anything other than GET/HEAD/OPTIONS) must also send
that value in the X-CSRF-Token header or they are rejected with 403.
NetavoBNG Management API v1#
Licensing#
GET /api/v1/licensing#
Licence status.
Description
The appliance's current licence state, band, metered counts and expiry/renewal timestamps. Any authenticated role.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
bearerToken |
header | string | N/A | No | Named API token — the recommended credential for automation. See Authentication in the API overview. |
Responses
{
"state": "Licensed",
"mode": "online",
"role": "bng",
"licenceId": "LIC-2026-0042",
"instanceId": "6f2c0a3e-8b41-4d92-9f0e-1c7d5a83b204",
"bandName": "10k",
"meter": "sessions",
"bandMax": 10000,
"currentCount": 1842,
"peakCount": 2104,
"expiresAtUtc": "2026-09-02T10:24:00Z",
"contractEndUtc": "2027-07-31T00:00:00Z",
"lastRenewalUtc": "2026-08-03T04:12:44Z",
"daysRemaining": 30,
"adminFreezeActive": false,
"isUnlicensed": false,
"isEnrolled": true
}
Schema of the response body
{
"required": [
"state",
"mode",
"role",
"licenceId",
"instanceId",
"bandName",
"meter",
"bandMax",
"currentCount",
"peakCount",
"expiresAtUtc",
"contractEndUtc",
"lastRenewalUtc",
"daysRemaining",
"adminFreezeActive",
"isUnlicensed",
"isEnrolled"
],
"type": "object",
"properties": {
"state": {
"type": "string",
"description": "Licence state machine value (e.g. \"Dev\", \"Licensed\", \"Grace\", \"Lapsed\")."
},
"mode": {
"type": "string",
"description": "Licensing mode configured on the box (e.g. \"dev\", \"online\", \"offline\")."
},
"role": {
"type": "string",
"description": "Licensed product role of the appliance."
},
"licenceId": {
"type": "string",
"description": "The licence this box is enrolled under, or null when unenrolled.",
"nullable": true
},
"instanceId": {
"type": "string",
"description": "This appliance's instance id under the licence, or null.",
"nullable": true
},
"bandName": {
"type": "string",
"description": "Capacity band name."
},
"meter": {
"type": "string",
"description": "What the band meters (e.g. sessions)."
},
"bandMax": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"description": "Metered cap of the band.",
"format": "int64"
},
"currentCount": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"description": "Current metered count.",
"format": "int64"
},
"peakCount": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"description": "Peak metered count in the current period.",
"format": "int64"
},
"expiresAtUtc": {
"type": "string",
"description": "Lease expiry, or null.",
"format": "date-time",
"nullable": true
},
"contractEndUtc": {
"type": "string",
"description": "Contract end date, or null.",
"format": "date-time",
"nullable": true
},
"lastRenewalUtc": {
"type": "string",
"description": "Last successful renewal, or null.",
"format": "date-time",
"nullable": true
},
"daysRemaining": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"description": "Days until lease expiry, or null.",
"format": "int32",
"nullable": true
},
"adminFreezeActive": {
"type": "boolean",
"description": "True when a lapsed licence freezes config commits."
},
"isUnlicensed": {
"type": "boolean",
"description": "True when the appliance has no usable licence."
},
"isEnrolled": {
"type": "boolean",
"description": "True when the appliance is enrolled with the licensing service."
}
},
"description": "GET /api/v1/licensing — the appliance's licence status.",
"example": {
"state": "Licensed",
"mode": "online",
"role": "bng",
"licenceId": "LIC-2026-0042",
"instanceId": "6f2c0a3e-8b41-4d92-9f0e-1c7d5a83b204",
"bandName": "10k",
"meter": "sessions",
"bandMax": 10000,
"currentCount": 1842,
"peakCount": 2104,
"expiresAtUtc": "2026-09-02T10:24:00Z",
"contractEndUtc": "2027-07-31T00:00:00Z",
"lastRenewalUtc": "2026-08-03T04:12:44Z",
"daysRemaining": 30,
"adminFreezeActive": false,
"isUnlicensed": false,
"isEnrolled": true
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
POST /api/v1/licensing/activate#
Activate the appliance against the licensing service.
Description
Enrols the appliance using an activation token issued with the licence. Works in every licence state — including lapsed (state 3), where it is the recovery path. Super-user only.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
bearerToken |
header | string | N/A | No | Named API token — the recommended credential for automation. See Authentication in the API overview. |
Request body
Other accepted types: application/*+json, text/json
Schema of the request body
{
"required": [
"token"
],
"type": "object",
"properties": {
"token": {
"type": "string",
"description": "Activation token issued with the licence."
},
"licenceId": {
"type": "string",
"description": "Licence id, when the token alone is ambiguous.",
"nullable": true
}
},
"description": "POST /api/v1/licensing/activate body.",
"example": {
"token": "bnglic_4f9a2c7e51b8",
"licenceId": "LIC-2026-0042"
}
}
Responses
Schema of the response body
{
"required": [
"activated",
"instanceId"
],
"type": "object",
"properties": {
"activated": {
"type": "boolean",
"description": "Always true on a 200."
},
"instanceId": {
"type": "string",
"description": "The instance id assigned by the licensing service.",
"nullable": true
}
},
"description": "POST /api/v1/licensing/activate result.",
"example": {
"activated": true,
"instanceId": "6f2c0a3e-8b41-4d92-9f0e-1c7d5a83b204"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
POST /api/v1/licensing/load-offline#
Install an offline licence lease.
Description
The request body is the signed offline lease JSON issued by Netavo (posted verbatim). It is persisted to the configured offline-licence path and applied immediately — the air-gapped alternative to online activation/renewal. Super-user only.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
bearerToken |
header | string | N/A | No | Named API token — the recommended credential for automation. See Authentication in the API overview. |
Request body
Responses
Schema of the response body
{
"required": [
"applied",
"state"
],
"type": "object",
"properties": {
"applied": {
"type": "boolean",
"description": "Always true on a 200."
},
"state": {
"type": "string",
"description": "Licence state after applying the offline lease."
}
},
"description": "POST /api/v1/licensing/load-offline result.",
"example": {
"applied": true,
"state": "Licensed"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
POST /api/v1/licensing/renew-now#
Renew the licence lease now.
Description
Contacts the licensing service immediately instead of waiting for the scheduled renewal, and returns the resulting state. Super-user only.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
bearerToken |
header | string | N/A | No | Named API token — the recommended credential for automation. See Authentication in the API overview. |
Responses
{
"renewed": true,
"state": "Licensed",
"expiresAtUtc": "2026-09-02T10:24:00Z",
"daysRemaining": 30
}
Schema of the response body
{
"required": [
"renewed",
"state",
"expiresAtUtc",
"daysRemaining"
],
"type": "object",
"properties": {
"renewed": {
"type": "boolean",
"description": "Always true on a 200."
},
"state": {
"type": "string",
"description": "Licence state after the renewal."
},
"expiresAtUtc": {
"type": "string",
"description": "New lease expiry, or null.",
"format": "date-time",
"nullable": true
},
"daysRemaining": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"description": "Days until the new expiry, or null.",
"format": "int32",
"nullable": true
}
},
"description": "POST /api/v1/licensing/renew-now result.",
"example": {
"renewed": true,
"state": "Licensed",
"expiresAtUtc": "2026-09-02T10:24:00Z",
"daysRemaining": 30
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
GET /api/v1/licensing/telemetry#
Preview the licensing telemetry payload.
Description
Returns the exact JSON payload the appliance sends to the licensing service at its next renewal (null fields omitted), so operators can audit what leaves the box. The shape follows the licensing telemetry contract (design doc 27), not a schema in this document; an empty object is returned when telemetry collection isn't running. Any authenticated role.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
bearerToken |
header | string | N/A | No | Named API token — the recommended credential for automation. See Authentication in the API overview. |
Responses
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
Schema of the response body
{
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"example": {
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "VRF not found",
"status": 404,
"detail": "No VRF named 'wholesale-b' is configured.",
"instance": "/api/v1/vrfs/wholesale-b"
}
}
Schemas#
ActivateRequest#
| Name | Type | Description |
|---|---|---|
licenceId |
string | null | Licence id, when the token alone is ambiguous. |
token |
string | Activation token issued with the licence. |
JsonElement#
Type:
LicenseActivateResult#
| Name | Type | Description |
|---|---|---|
activated |
boolean | Always true on a 200. |
instanceId |
string | null | The instance id assigned by the licensing service. |
LicenseOfflineResult#
| Name | Type | Description |
|---|---|---|
applied |
boolean | Always true on a 200. |
state |
string | Licence state after applying the offline lease. |
LicenseRenewResult#
| Name | Type | Description |
|---|---|---|
daysRemaining |
Days until the new expiry, or null. | |
expiresAtUtc |
string(date-time) | null | New lease expiry, or null. |
renewed |
boolean | Always true on a 200. |
state |
string | Licence state after the renewal. |
LicensingStatus#
| Name | Type | Description |
|---|---|---|
adminFreezeActive |
boolean | True when a lapsed licence freezes config commits. |
bandMax |
Metered cap of the band. | |
bandName |
string | Capacity band name. |
contractEndUtc |
string(date-time) | null | Contract end date, or null. |
currentCount |
Current metered count. | |
daysRemaining |
Days until lease expiry, or null. | |
expiresAtUtc |
string(date-time) | null | Lease expiry, or null. |
instanceId |
string | null | This appliance's instance id under the licence, or null. |
isEnrolled |
boolean | True when the appliance is enrolled with the licensing service. |
isUnlicensed |
boolean | True when the appliance has no usable licence. |
lastRenewalUtc |
string(date-time) | null | Last successful renewal, or null. |
licenceId |
string | null | The licence this box is enrolled under, or null when unenrolled. |
meter |
string | What the band meters (e.g. sessions). |
mode |
string | Licensing mode configured on the box (e.g. "dev", "online", "offline"). |
peakCount |
Peak metered count in the current period. | |
role |
string | Licensed product role of the appliance. |
state |
string | Licence state machine value (e.g. "Dev", "Licensed", "Grace", "Lapsed"). |
ProblemDetails#
| Name | Type | Description |
|---|---|---|
detail |
string | null | |
instance |
string | null | |
status |
||
title |
string | null | |
type |
string | null |
Security schemes#
| Name | Type | Scheme | Description |
|---|---|---|---|
| bearerToken | http | bearer | Named API token — the recommended credential for automation. See Authentication in the API overview. |
| sessionCookie | apiKey | Interactive session cookie used by the bundled web UI. Not the integration path for API clients — use a bearer token. See Authentication in the API overview. |
Tags#
| Name | Description |
|---|---|
| Licensing | Licence status, telemetry preview, activation, renewal, and offline licence install. |