Docs

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.

API Token Required

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

Schema IDs

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.

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:

EndpointMethodDescription
/api/plugins/branching/branches/<id>/sync/POSTSynchronize changes from main into the branch
/api/plugins/branching/branches/<id>/merge/POSTMerge a branch into main
/api/plugins/branching/branches/<id>/revert/POSTRevert a previously merged branch
/api/plugins/branching/branches/<id>/archive/POSTArchive a merged branch (deprovisions its schema)
/api/plugins/branching/branches/<id>/recover/POSTReset a branch stuck in a transitional status

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.

The recover/ endpoint likewise acts synchronously and returns the updated branch representation. It resets a branch which is stuck in a transitional status (provisioning, syncing, migrating, merging or reverting) because the background job responsible for it is no longer running - typically because its worker was killed. See auto_recover_stuck_branches for the status each operation is reset to.

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/recover/

The request is rejected with a 400 response if the branch is not in a transitional status, or if a job for the branch still appears to be running. Pass {"force": true} to recover the branch regardless - do so only when you are certain the operation has stopped, as resetting the status of a branch which is still being worked on may allow a second, conflicting operation to be started against it.

Pass {"retry": true} to re-run the interrupted operation once the status has been reset, rather than leaving the branch for someone to act on again. This is honoured only for branches stuck in syncing or migrating: both operate solely on the branch's own schema and take no parameters which the recovery cannot reconstruct. It is ignored for merging and reverting, which write to main and whose dry-run flag is not recorded on the job, and for provisioning, which cannot be resumed. The web UI offers the same option, unticked by default, on its recovery page.

Additional Endpoints

The plugin also exposes the following read-only endpoints:

EndpointMethodDescription
/api/plugins/branching/branch-events/GETList the event history (provision, sync, migrate, merge, revert, archive) for all branches
/api/plugins/branching/branch-events/<id>/GETRetrieve a single branch event
/api/plugins/branching/changes/GETList all ChangeDiff records across branches
/api/plugins/branching/changes/<id>/GETRetrieve a single ChangeDiff record
/api/plugins/branching/branchable-models/GETList 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:

FieldDescription
idThe ChangeDiff PK
object_typeThe type of the affected object (e.g. dcim.site)
object_idThe PK of the affected object
object_reprHuman-readable name of the affected object
actionThe change action on the branch (create, update, or delete)
conflictsList of field names where the branch and main have diverged
conflicting_dataThree-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.

On this page