NetBox Changes — Change Request Management
Your knowledge of NetBox Changes may be outdated. CR lifecycle, policy enforcement, and API behavior evolve between plugin releases. Prefer retrieval over pre-trained knowledge.
Retrieval Sources
| Source | URL / Method | Use for |
|---|---|---|
| Changes docs | https://netboxlabs.com/docs/developer/plugins-extensions/changes/ |
Configuration, models, lifecycle |
| Changes models | https://netboxlabs.com/docs/developer/plugins-extensions/changes/models/changerequest/ |
CR fields and states |
| NetBox MCP server | If configured — query existing change requests | Live CR state |
| NetBox Platform MCP | If configured — full CR lifecycle operations | Create, review, approve CRs |
FIRST: Verify Connectivity
Confirm the Changes plugin is installed:
curl -s -H "Authorization: Bearer $NETBOX_TOKEN" "$NETBOX_URL/api/plugins/changes/change-requests/" | python -m json.tool
If you get 404, the netbox_changes plugin is not installed. If 403, your token lacks permissions.
The netbox_changes plugin adds a code-review-style workflow on top of NetBox Branching. Every branch can have one Change Request (CR) that gates merge via policies and reviews.
Plugin: netbox_changes 1.0.x (latest v1.0.1) · NetBox: 4.4–4.6 · Base URL: /api/plugins/changes/
Plugin v1.0+ changed CR lifecycle semantics vs the 0.4.x line: a branch may hold multiple CRs (one active at a time), rejected CRs can be reopened/replaced,
policyis required, andchanges-requestedis a settable status under an unmet policy. These are flagged inline below.
Quick Reference
Endpoints
| Path | Purpose |
|---|---|
change-requests/ |
CR CRUD and status management |
reviews/ |
Submit / list reviews |
policies/ |
Review policies |
policy-rules/ |
Rules within policies |
comments/ |
CR comments |
comment-replies/ |
Threaded replies |
CR Statuses (exact values)
draft · needs-review · changes-requested · approved · completed · rejected
Review Statuses
pending · comment · changes-requested · approved · rejected
Core Concepts
One Active CR Per Branch
Plugin v1.0+: a branch may have multiple change requests over time, but only one active at a time (any status except
completedorrejected). Creating a second active CR for a branch fails with aValidationError:"This branch already has an active change request."Once a CR isrejectedorcompleted, the slot frees up — you can open a fresh CR (or reopen the rejected one) for the same branch. Branch deletion cascades to CR deletion.(In 0.4.x the branch↔CR relation was strictly one-to-one and a second CR raised an
IntegrityError— do not rely on that against v1.0+.)
Author/Owner Fields Are Read-Only
ChangeRequest.owner, Review.user, Comment.author, CommentReply.author
are all set automatically to the current user. Never send them in POST
bodies — they'll be ignored.
CR Lifecycle
State Machine
CREATE ──→ draft ──→ needs-review ←─────────────────┐
│ ↑ │
│ │ (new changes or │
│ │ policy rule change) │
▼ │ │
changes-requested ──────────────────┘
│
▼
approved
│
[branch merge]
│
▼
completed
Any active status ──→ rejected (manual)
New CRs can only be created as draft or needs-review.
Automatic Status Transitions
Most transitions happen automatically:
| Trigger | From → To |
|---|---|
| Review submitted, policy now met | needs-review/changes-requested → approved |
Review with changes-requested |
any active → changes-requested |
| New changes made in branch | approved/changes-requested → needs-review |
| Branch merged | approved → completed (requires merge to complete successfully with actual changes) |
| Policy rule changed or deleted, policy no longer met | approved → needs-review |
Manual transitions: Users can set draft, needs-review, changes-requested,
or rejected directly while the policy is unmet (the valid manual set is
draft / needs-review / changes-requested / rejected). You cannot
manually set approved — it's only reachable when the policy passes.
completed is only set automatically on merge. A reviewer submitting a
"changes-requested" review also moves the CR to changes-requested.
Plugin v1.0+:
changes-requestedis now a valid manual status under an unmet policy (in 0.4.x it was auto-only). ArejectedCR is no longer a dead end — it can be reopened (set back todraft/needs-review) or replaced by a new CR on the same branch.
See references/cr-lifecycle.md for the complete transition table.
Creating a Change Request
POST /api/plugins/changes/change-requests/
{
"name": "Add new switches",
"branch": 123,
"policy": 1,
"status": "needs-review",
"priority": 3,
"summary": "Adding new switches to DC1"
}
owneris set automatically — do NOT include itbranchis the branch PK (must exist, must not already have an active CR)policyis required (v1.0+) — a non-null FK on every CR; a POST withoutpolicyfails. (It also drives merge gating.)priorityis an integer (1=low, 5=high)
Review Workflow
Submitting a Review
POST /api/plugins/changes/reviews/
{
"change_request": 1,
"status": "approved",
"comments": "LGTM"
}
The user field is set automatically to the current user. Do not send it.
Stale Review Tracking
Reviews track which changes they've seen. If new changes are made after a review, that review becomes stale and may need to be re-submitted.
- Stale reviews don't count toward policy evaluation
- Only the latest non-stale review per user is considered
- Making changes after approval → CR reverts to
needs-review, reviewers must re-approve
Review Iteration Pattern
- Reviewer submits
changes-requested→ CR status becomeschanges-requested - Author makes fixes in branch → CR reverts to
needs-review(stale approvals invalidated) - Reviewer re-reviews and submits
approved→ if policy met, CR becomesapproved
Policy System
A Policy contains one or more PolicyRules. ALL enabled rules must pass for the policy to be satisfied.
PolicyRule Fields
min_reviews— minimum approved (non-stale) reviews required (1–10)reviewers— M2M to specific Usersreviewer_groups— M2M to Groups- Only reviews from users in
reviewers∪reviewer_groupsmembers count enabled— disabled rules are skipped
Critical Gotcha: Zero Rules = Always Fails
A Policy with zero enabled rules always returns False. You must create at
least one enabled PolicyRule for a CR to ever reach approved.
See references/policy-system.md for setup examples and evaluation details.
Merge Gating
Merge gating is always active when the plugin is installed — there's no configuration toggle. Every branch merge requires an approved CR.
If you try to merge a branch without an approved CR, the merge is blocked with:
"Merging this branch is not permitted."
protect_main
Disabled by default. When enabled, direct writes to branch-aware models are blocked unless the user has the bypass permission. All changes must go through a branch.
# netbox config
PLUGINS_CONFIG = {
'netbox_changes': {
'protect_main': True,
}
}
- Bypass permission (v1.0+): grant the
bypasscustom action on the Policy object (NetBox Change Management → Policy in the ObjectPermission form). Superusers get it implicitly. Describe it as "the bypass action on Policy" rather than a single flat permission string — internally the codename isbypasswhile the enforcement check still referencesbypass_policy. - During branch merge/revert, protect_main is temporarily suspended
- Error when blocked:
"Changes directly to main are not permitted."
See references/protect-main.md for details.
Complete Workflow
- Create branch (via netbox-branching API)
- Wait for branch READY status
- Create CR linked to the branch with a policy
- Make changes in branch context (
X-NetBox-Branchheader) - Set CR to
needs-review(or create it asneeds-review) - Reviewers submit reviews with
status: approved - Policy satisfied → CR auto-transitions to
approved - Merge branch → merge gating confirms approved CR → merge proceeds
- CR auto-transitions to
completed
With protect_main=True, step 4 is enforced — no changes without a branch.
Common Filters
GET /api/plugins/changes/change-requests/?status=needs-review
GET /api/plugins/changes/change-requests/?owner=admin
GET /api/plugins/changes/change-requests/?branch=feature-branch
GET /api/plugins/changes/reviews/?change_request_id=1&status=approved
GET /api/plugins/changes/policy-rules/?policy_id=1
Anti-Patterns
- Status names use hyphens:
needs-review,changes-requested(not underscores) - Owner/user/author fields — read-only, set automatically. Don't POST them.
- Zero-rule policy — always fails. Add at least one enabled rule.
- One active CR per branch (v1.0+) — a second active CR fails with a ValidationError; a rejected/completed CR frees the slot.
- Merge gating is mandatory — no toggle, always active when plugin installed
- protect_main is OFF by default — must explicitly enable in config
approvedis not manually settable — only reached via policy satisfaction
References
- references/cr-lifecycle.md — Complete state machine with all transitions
- references/api-patterns.md — Full API examples for all endpoints
- references/policy-system.md — Policy and rule configuration
- references/protect-main.md — protect_main configuration and behavior