Using the REST API
This plugin includes support for activating and deactivating branches via the REST API in addition to conventional creation, modification, and deletion operations.
You'll need a valid NetBox REST API token to follow any of the examples shown here. API tokens can be provisioned by navigating to the API tokens list in the user menu.
Creating a Branch
Branches are created in a manner similar to most objects in NetBox. A POST request (including a valid authentication token) is sent to the branches/ API endpoint with the desired attributes, such as name and description:
curl -X POST \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json; indent=4" \
http://netbox:8000/api/plugins/branching/branches/ \
--data '{"name": "Branch 1", "description": "My new branch"}'
{
"id": 2,
"url": "http://netbox:8000/api/plugins/branching/branches/2/",
"display": "Branch 1",
"name": "Branch 1",
"status": "new",
"owner": {
"id": 1,
"url": "http://netbox:8000/api/users/users/1/",
"display": "admin",
"username": "admin"
},
"description": "My new branch",
"schema_id": "td5smq0f",
"last_sync": null,
"merged_time": null,
"merged_by": null,
"comments": "",
"tags": [],
"custom_fields": {},
"created": "2024-08-12T17:07:46.196956Z",
"last_updated": "2024-08-12T17:07:46.196970Z"
}
Once a new branch has been created, it will be provisioned automatically, just as when one is created via the web UI. The branch's status will show "ready" when provisioning has completed.
Once provisioned, branches can be modified and deleted via the /api/plugins/branching/branches/<id>/ endpoint, similar to most objects in NetBox.
Activating a Branch
Unlike the web UI, where a user's selected branch remains active until it is changed, the desired branch must be specified with each REST API request. This is accomplished by including the X-NetBox-Branch HTTP header specifying the branch's schema ID.
X-NetBox-Branch: $SCHEMA_ID
The schema ID for a branch can be found in its REST API representation or on its detail view in the web UI. This is a pseudorandom eight-character alphanumeric identifier generated automatically when a branch is created. Note that the value passed to the HTTP header does not include the branch_ prefix, which comprises part of the schema's name in the underlying database.
The example below returns all site objects that exist within the branch with schema ID td5smq0f:
curl -X POST \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json; indent=4" \
-H "X-NetBox-Branch: td5smq0f" \
http://netbox:8000/api/dcim/sites/
The branch is effectively "deactivated" for future API requests by simply omitting the header.
!!! note
The X-NetBox-Branch header is required only when making changes to NetBox objects within the context of an active branch. It is not required when creating, modifying, or deleting a branch itself.
Branch Actions
Several REST API endpoints are provided to handle the lifecycle actions associated with a branch:
| Endpoint | Method | Description |
|---|---|---|
/api/plugins/branching/branches/<id>/sync/ | POST | Synchronize changes from main into the branch |
/api/plugins/branching/branches/<id>/merge/ | POST | Merge a branch into main |
/api/plugins/branching/branches/<id>/revert/ | POST | Revert a previously merged branch |
/api/plugins/branching/branches/<id>/archive/ | POST | Archive a merged branch (deprovisions its schema) |
To synchronize updates from main into a branch, send a POST request to the desired branch's sync/ endpoint.
The sync/, merge/, and revert/ endpoints accept a commit argument: setting this to false performs a dry run, where the changes are automatically rolled back at the end of the job. (This can be helpful to check for potential errors before committing to a set of changes.) The default value is true.
curl -X POST \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json; indent=4" \
http://netbox:8000/api/plugins/branching/branches/2/sync/ \
--data '{"commit": true}'
If successful, this will return data about the background job that has been enqueued to handle the synchronization of data. This job can be queried to determine the progress of the synchronization.
{
"id": 4,
"url": "http://netbox:8000/api/core/jobs/4/",
"display_url": "http://netbox:8000/core/jobs/4/",
"display": "f0c6dea2-d5bb-4683-851e-2ac705510af4",
"object_type": "netbox_branching.branch",
"object_id": 2,
"name": "Sync branch",
"status": {
"value": "pending",
"label": "Pending"
},
"created": "2024-08-12T17:27:57.448405Z",
"scheduled": null,
"interval": null,
"started": null,
"completed": null,
"user": {
"id": 1,
"url": "http://netbox:8000/api/users/users/1/",
"display": "admin",
"username": "admin"
},
"data": null,
"error": "",
"job_id": "f0c6dea2-d5bb-4683-851e-2ac705510af4"
}
This same pattern can be followed to merge and revert branches via their respective API endpoints, listed above.
The archive/ endpoint differs slightly: it does not enqueue a background job, but rather archives the branch synchronously and returns the updated branch representation. The branch must be in the merged state for this action to succeed.
Additional Endpoints
The plugin also exposes the following read-only endpoints:
| Endpoint | Method | Description |
|---|---|---|
/api/plugins/branching/branch-events/ | GET | List the event history (provision, sync, migrate, merge, revert, archive) for all branches |
/api/plugins/branching/branch-events/<id>/ | GET | Retrieve a single branch event |
/api/plugins/branching/changes/ | GET | List all ChangeDiff records across branches |
/api/plugins/branching/changes/<id>/ | GET | Retrieve a single ChangeDiff record |
/api/plugins/branching/branchable-models/ | GET | List every model registered for branching support |
Syncing & Merging with Conflicts
If conflicting changes exist on a branch (i.e. the same object has been modified in both main and the branch since the last sync), the sync/ and merge/ endpoints will return HTTP 409 Conflict rather than enqueuing a job. The response body includes a detail message and a conflicts list describing each conflicting change:
{
"detail": "All conflicts must be acknowledged before this action can proceed.",
"conflicts": [
{
"id": 6,
"object_type": "dcim.site",
"object_id": 31,
"object_repr": "s1",
"action": {
"value": "update",
"label": "Updated"
},
"conflicts": ["description", "tags"],
"conflicting_data": {
"original": {
"description": "",
"tags": []
},
"branch": {
"description": "abc",
"tags": ["Alpha", "Foxtrot"]
},
"main": {
"description": "def",
"tags": ["Alpha", "Charlie", "Delta"]
}
},
"last_updated": "2024-08-12T17:07:10.442432Z"
}
]
}
Each entry in conflicts corresponds to a ChangeDiff record and includes:
| Field | Description |
|---|---|
id | The ChangeDiff PK |
object_type | The type of the affected object (e.g. dcim.site) |
object_id | The PK of the affected object |
object_repr | Human-readable name of the affected object |
action | The change action on the branch (create, update, or delete) |
conflicts | List of field names where the branch and main have diverged |
conflicting_data | Three-way view of the conflicting fields: original (at branch creation), branch (branch value), main (current main value) |
Full details for any conflict can be retrieved via the change diff endpoint:
curl -X GET \
-H "Authorization: Token $TOKEN" \
-H "Accept: application/json; indent=4" \
http://netbox:8000/api/plugins/branching/changes/6/
Acknowledging Conflicts
To proceed despite conflicts, include "acknowledge_conflicts": true in the request body. This signals that you have reviewed the conflicts and accept that the branch's version of the affected fields will overwrite whatever is currently in main.
curl -X POST \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json; indent=4" \
http://netbox:8000/api/plugins/branching/branches/2/sync/ \
--data '{"commit": true, "acknowledge_conflicts": true}'
Acknowledging conflicts means the branch's version of all conflicting fields will overwrite whatever is currently in main. Review conflicting_data carefully before proceeding.