REST API¶
Everything the matrix page does goes through the endpoints under /api/plugins/permissions-matrix/. Use them to
script permission changes with the same safety rules as the page: plan first, review, then apply with the token the
plan returned.
Authenticate as for any NetBox API call, with a token:
export NETBOX=https://netbox.example.com
export TOKEN="nbt_xxxxxxxx.yyyyyyyy"
curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" "$NETBOX/api/plugins/permissions-matrix/matrix/?action=change"
The same permissions as on the page apply. plan/ and apply/ also need a token with
Write enabled set: a read-only token can read the matrix but not plan or apply changes.
GET matrix/¶
The matrix for one action, or for every action at once.
| Parameter | Default | Meaning |
|---|---|---|
action |
view |
The action: view, add, change, delete, a registered custom action, or any other action name. * returns every action (see below). |
include_users |
the show_users_by_default setting |
true adds a column for every user with a permission assigned directly. |
group_id |
all groups | Only these groups. Repeat the parameter for several. |
user_id |
These users, whether or not they have direct permissions. Implies user columns. | |
app_label |
all apps | Only rows of these apps. Repeat for several. |
The response:
{
"action": "change",
"can_edit": true,
"actions": [{"name": "view", "label": "View", "custom": false, "freeform": false, "help_text": ""}],
"rows": [{"object_type": "dcim.device", "app_label": "dcim", "app_name": "DCIM", "label": "Device", "enabled": true}],
"columns": [
{"type": "group", "id": 1, "key": "group:1", "name": "NOC", "simple": null, "others": []}
],
"cells": {
"group:1": {
"dcim.device": {"state": "granted", "perms": [{"id": 4, "name": "NOC-RW", "enabled": true, "constrained": false}]}
}
}
}
cellslists only cells something covers; a missing cell isnone.stateisgranted,constrained,disabledornone; see Cell states.- A user cell can carry
"inherited": {"state": "granted", "groups": ["NOC"]}: access through group membership, which the user column never edits. columns[].simpleis the principal's permission holding only this one action, unconstrained, if there is one, andcolumns[].othersevery other permission granting it the action. This is narrower than a simple permission in How changes map to permissions:noc_vais simple there but appears underothersfor view.- Permission objects in
perms,simpleandothersalso carrydescription,actions,object_types,constraints,principalsandurl. - Groups and users you may not view are not named: in
principalsandinherited.groupstheir name reads "a group you cannot view" or "a user you cannot view".
With action=* the response has "action": "*" and three differences:
cellshas one more level, the action:cells["group:1"]["dcim.device"]["change"].rows[].enabled_actionslists the actions that apply to the row, in place ofrows[].enabled.columns[].permslists every permission assigned to the principal, in place ofsimpleandothers.
GET principal/¶
One group's or user's cells for every action, as the group tab shows them.
| Parameter | Meaning |
|---|---|
type |
group or user. |
id |
The group's or user's ID. Unknown, or not visible to you, gives HTTP 404. |
The response has principal (type, id, key, name), can_edit, actions and rows as for matrix/
(rows carry enabled_actions), columns keyed by action name, each with simple and others as above, and
cells keyed by object type then action: cells["dcim.device"]["change"].
Change sets¶
plan/ and apply/ take the same body:
{
"changes": [
{"principal": {"type": "group", "id": 1}, "object_type": "dcim.site", "action": "change", "granted": false},
{"principal": {"type": "user", "id": 7}, "object_type": "ipam.prefix", "action": "view", "granted": true}
],
"edits": [
{"principal": {"type": "group", "id": 1}, "perm_id": 12, "constraints": {"tenant__slug": "acme"}}
]
}
changes: cells to grant (true) or revoke (false). If a cell appears twice, the last entry wins.edits: changes to one of a principal's permissions, as in the gear panel. Giveperm_id, the ID of a permission assigned to the principal. The older form withactioninstead still works, but only finds a permission holding that one action and nothing else, unconstrained: with permissions named by action set (noc_va), it usually finds nothing and the plan warns. Give one ofperm_idandaction, not both. An unknownperm_id, or a permission also assigned to groups or users you cannot see, is refused with HTTP 400. Optional fields:name,description,enabled,constraints(an object, a list of objects, ornullto remove them),add_actions,add_groups,add_users(IDs). An edit naming a permission not assigned to the principal is left out, with a warning.
object_type must be one NetBox allows in a permission. Unknown groups or users, invalid action names and invalid
constraints are refused with HTTP 400.
POST plan/¶
A dry run. Nothing is written.
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
"$NETBOX/api/plugins/permissions-matrix/plan/" \
-d '{"changes": [{"principal": {"type": "group", "id": 1}, "object_type": "dcim.site", "action": "change", "granted": false}]}'
{
"token": "3f1c...",
"warnings": [],
"operations": [
{"op": "update", "key": "4", "id": 4, "before": {"name": "NOC-RW"}, "after": {"name": "NOC-RW"},
"affects": [{"type": "group", "id": 1, "name": "NOC"}],
"reasons": ["Remove NOC, who loses change dcim.site; other assignees unchanged"]},
{"op": "create", "key": "new-1", "id": null, "before": null, "after": {"name": "NOC-RW (NOC)"},
"affects": [{"type": "group", "id": 1, "name": "NOC"}],
"reasons": ["Keep what NOC had from NOC-RW, without change dcim.site"]}
]
}
before and after are full permission objects (shortened above). affects lists the principals whose access the
operation changes. The planning rules explain why each operation is there.
POST apply/¶
The same body plus the token from plan/:
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
"$NETBOX/api/plugins/permissions-matrix/apply/" \
-d '{"changes": [...], "token": "3f1c..."}'
The server plans the change set again and compares tokens. The response is the plan plus written, the list of
permissions created, changed and deleted (op, id, name).
| Status | Meaning |
|---|---|
| 200 | Applied. Everything in written is saved. |
| 400 | The change set is invalid, or token is missing. |
| 403 | The token is not write-enabled, you may not use the matrix, or not add, change or delete one of the permissions in the plan. Nothing was written. |
| 409 | A permission the plan depends on changed after plan/, a name the plan gives was taken, or a group or user in it was deleted during the apply. Nothing was written: plan again. |
The whole apply runs in one database transaction, with the permission table locked against other writers, so it either applies completely or not at all.
POST import/¶
Reads a file made by export and returns the cell changes that would make it true. Nothing is
written: send the changes to plan/ and apply/.
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
"$NETBOX/api/plugins/permissions-matrix/import/" \
-d "$(jq -n --rawfile yaml matrix.yaml '{yaml: $yaml}')"
{
"changes": [
{"principal": {"type": "group", "id": 2}, "name": "Ops", "object_type": "dcim.site", "action": "view",
"granted": false}
],
"warnings": [],
"errors": ["Unknown group 'Ghosts': its entries are skipped."]
}
Each change has the shape plan/ takes, plus name for display, which plan/ ignores. Post the list as changes.
| Status | Meaning |
|---|---|
| 200 | The file was read. errors lists skipped entries, warnings cells left unchanged. |
| 400 | yaml is missing or empty, the text is not valid YAML, or it uses anchors and aliases. |
| 403 | The token is not write-enabled, or you may not add, change or delete permissions. |