Docs

REST API

The NetBox Custom Objects plugin exposes full CRUD operations through the standard NetBox REST API, rooted at /api/plugins/custom-objects/. The root of the API lists endpoints for Custom Object Types, their fields and constraints, the linked-objects helper, and a dynamically generated endpoint for each Custom Object Type you can view:

{
    "custom-object-type-constraints": "https://netbox/api/plugins/custom-objects/custom-object-type-constraints/",
    "custom-object-type-fields": "https://netbox/api/plugins/custom-objects/custom-object-type-fields/",
    "custom-object-types": "https://netbox/api/plugins/custom-objects/custom-object-types/",
    "linked-objects": "https://netbox/api/plugins/custom-objects/linked-objects/",
    "dhcp_scope": "https://netbox/api/plugins/custom-objects/dhcp_scope/"
}

The endpoint name for each Custom Object Type is its slug - a type with slug dhcp_scope is reachable at /api/plugins/custom-objects/dhcp_scope/.

Requests are authenticated as for the rest of NetBox's REST API, and NetBox's object permissions apply. For example, to list the objects of a type with a v2 token:

curl -H "Authorization: Bearer nbt_<key>.<token>" \
     -H "Accept: application/json" \
     https://netbox/api/plugins/custom-objects/dhcp_scope/

The examples below show the JSON body of each request; send it with -H "Content-Type: application/json" and --data.

For schema management - exporting Custom Object Type definitions, previewing diffs, and applying schemas to other instances - see the Portable Schema documentation, which also covers the schema/preview/ and schema/apply/ endpoints.

Custom Object Types

Create a Custom Object Type with a POST to /api/plugins/custom-objects/custom-object-types/:

{
  "name": "server",
  "slug": "server",
  "description": "Server inventory objects",
  "verbose_name": "Server",
  "verbose_name_plural": "Servers"
}
FieldRequiredDescription
nameyesInternal name. Must be lowercase alphanumeric with underscores only (e.g. dhcp_scope). Must be unique.
slugyesURL-safe slug used in API paths and navigation. Must be unique.
verbose_namenoSingular display name shown in the UI. Defaults to the title-cased name.
verbose_name_pluralnoPlural display name. Defaults to verbose_name + "s".
descriptionnoShort description (max 200 characters).
versionnoPEP 440 version string (e.g. 1.0.0). Used by the portable schema feature.
group_namenoGroups similar Custom Object Types together in the navigation menu.
display_expressionnoJinja expression that renders each object's display name, e.g. {{ hostname }} ({{ cpu_cores }} cores). Overrides the primary field.
config_context_enablednoGives objects of this type config context support (see Config context). Can only be set when the type is created. Default: false.
tagsnoList of NetBox tag IDs to attach to this Custom Object Type.

Responses also include the type's fields (each field's full representation), its schema_document (see Portable Schema), and the read-only table_model_name and object_type_name of the model that backs the type.

Custom Object Type Fields

Define the schema of a Custom Object Type by creating fields with POST requests to /api/plugins/custom-objects/custom-object-type-fields/, referencing the ID of the Custom Object Type:

{
  "custom_object_type": 9,
  "name": "internal_id",
  "label": "Internal ID",
  "type": "integer",
  "required": true,
  "validation_minimum": 0,
  "validation_maximum": 9999
}

Available type values are:

TypeDescription
textShort text field
longtextLong text field with textarea widget
integerInteger number
decimalDecimal number
booleanTrue/false
dateDate
datetimeDate and time
urlURL
jsonJSON value
selectSingle selection from a choice set
multiselectMultiple selections from a choice set
objectReference to a single object
multiobjectReference to multiple objects of the same type
colorRGB color as six lowercase hexadecimal digits, e.g. 00ff00
mac_addressEUI-48 MAC address; accepted in any common format, returned as 00:1A:2B:3C:4D:5E
arrayList of values (or of fixed-size tuples) of one element type
coordinatesLatitude and longitude

Common attributes available on all field types:

AttributeRequiredDescription
nameyesInternal field name. Must be lowercase alphanumeric with underscores only (e.g. rack_unit). Must be unique within the Custom Object Type.
typenoField type (see table above). Default: text.
labelnoDisplay name shown in the UI. Defaults to name with underscores replaced by spaces and the first letter capitalized.
descriptionnoHelp text shown in forms.
group_namenoFields sharing the same group name are displayed together.
requirednoWhether a value must be provided. Default: false.
uniquenoWhether values must be unique across all objects of this type. Default: false. Not supported for boolean, multiobject or coordinates fields.
primarynoWhether this field's value is used as the object's display name.
contextnoWhether this field's value is shown when the object is referenced by another object.
defaultnoDefault value (must be a valid JSON value).
weightnoDisplay order weight. Higher values appear lower. Default: 100.
search_weightnoSearch relevance weight. Lower values are more important; 0 disables search indexing. Default: 500.
filter_logicno"loose" (substring match), "exact" (exact match), or "disabled". Default: "loose".
ui_visibleno"always", "if-set", or "hidden". Default: "always".
ui_editableno"yes", "no" (read-only), or "hidden". Default: "yes".
is_cloneablenoWhether the field value is copied when cloning an object. Default: false.
commentsnoFree-form notes about this field (supports Markdown).
deprecatednoMarks the field as deprecated. This is informational only: the field keeps working as before. It can't be set in the web UI. Default: false.
deprecated_sincenoPEP 440 version string when the field was deprecated (e.g. "2.0.0").
scheduled_removalnoPEP 440 version string when the field is planned for removal (e.g. "3.0.0").
schema_id(read-only)Stable, auto-assigned identifier used by the portable schema feature. See Portable Schema.

Text Fields

Field types: text, longtext (and url, below)

{
  "custom_object_type": 9,
  "name": "hostname",
  "label": "Hostname",
  "type": "text",
  "required": true,
  "validation_regex": "^[a-zA-Z0-9-]+$"
}
AttributeDescription
validation_regexRegular expression enforced on field values.

URL Fields

Field type: url

A URL field also accepts validation_regex. Each object stores a link title alongside the URL, which the API reads and writes as <name>_title, e.g. "docs": "https://wiki.example.com/server-001", "docs_title": "Runbook".

Coordinates Fields

Field type: coordinates

A coordinates field stores a latitude and a longitude. Each object reads and writes them as two values, <name>_latitude and <name>_longitude, e.g. "location_latitude": 40.7128, "location_longitude": -74.006. Set both or neither.

Numeric Fields

Field types: integer, decimal

{
  "custom_object_type": 9,
  "name": "cpu_cores",
  "label": "CPU Cores",
  "type": "integer",
  "validation_minimum": 1,
  "validation_maximum": 128
}
AttributeDescription
validation_minimumMinimum allowed value.
validation_maximumMaximum allowed value.

Array Fields

Field type: array

{
  "custom_object_type": 9,
  "name": "waypoints",
  "label": "Waypoints",
  "type": "array",
  "array_element_type": "integer",
  "array_tuple_size": 3,
  "array_min_length": 2
}
AttributeDescription
array_element_typetext, integer, decimal, boolean, date or datetime. Required. Cannot be changed after creation.
array_tuple_sizeStore a list of tuples of this many values (at least 2); null for a list of single values. Cannot be changed after creation.
array_min_length, array_max_lengthMinimum and maximum number of items (at least 1 when set).
validation_regexFor text elements: a regular expression every value must match.
validation_minimum, validation_maximumFor integer and decimal elements: the allowed range of every value.

An object's value is a JSON list, e.g. "waypoints": [[0, 0, 0], [10, 0, 5]].

Choice Fields

Field types: select, multiselect

{
  "custom_object_type": 9,
  "name": "environment",
  "label": "Environment",
  "type": "select",
  "choice_set": 5
}
AttributeDescription
choice_setID of a NetBox Custom Field Choice Set. Required.

Object Reference Fields

Field types: object, multiobject

For non-polymorphic object or multiobject fields, specify the content type using app_label and model:

{
  "custom_object_type": 9,
  "name": "primary_device",
  "label": "Primary Device",
  "type": "object",
  "app_label": "dcim",
  "model": "device"
}
{
  "custom_object_type": 9,
  "name": "device_list",
  "label": "Device List",
  "type": "multiobject",
  "app_label": "dcim",
  "model": "device"
}

Additional attributes for object reference fields:

AttributeDescription
app_labelDjango app label of the related model (write-only). Required for non-polymorphic object fields.
modelModel name of the related model (write-only). Required alongside app_label.
related_object_type(read-only) Nested representation of the referenced object type.
is_polymorphicWhen true, the field accepts references to objects of multiple different types. Requires related_object_types_input instead of app_label/model. Cannot be changed after the field is created. Default: false.
related_object_types_inputList of {"app_label": ..., "model": ...} dicts (write-only). Required for polymorphic fields.
related_object_types(read-only) The allowed object types for polymorphic fields, as a list of {"id": ..., "app_label": ..., "model": ...}.
related_object_filterJSON query_params dict used to filter the object selection drop-down.
related_nameReverse relation accessor name on the related object (e.g. ssl_profiles allows obj.ssl_profiles.all()).
on_delete_behaviorAction when the referenced object is deleted: "set_null" (default), "cascade", or "protect". Applies only to object fields. Creating any other type of field with it returns 400 Bad Request.

An object or multiobject field can reference any Custom Object Type as well as any core NetBox object. To reference another Custom Object Type, set app_label to "custom-objects" and model to the target Custom Object Type's slug. For example:

{
  "custom_object_type": 9,
  "name": "parent_circuit",
  "type": "object",
  "app_label": "custom-objects",
  "model": "circuit"
}

Polymorphic Object Reference Fields

A polymorphic object or multiobject field can reference objects of multiple different types. Set is_polymorphic: true and provide the allowed types via related_object_types_input:

{
  "custom_object_type": 9,
  "name": "linked_resource",
  "label": "Linked Resource",
  "type": "object",
  "is_polymorphic": true,
  "related_object_types_input": [
    {"app_label": "dcim", "model": "device"},
    {"app_label": "dcim", "model": "rack"},
    {"app_label": "custom-objects", "model": "server"}
  ]
}

The is_polymorphic flag and the set of allowed related_object_types cannot be changed after the field is created. To convert between a polymorphic and a non-polymorphic field, delete and recreate the field.

Custom Object Type Constraints

Require a combination of field values to be unique by creating a constraint with a POST request to /api/plugins/custom-objects/custom-object-type-constraints/. fields lists the IDs of the fields it covers:

{
  "custom_object_type": 9,
  "name": "vendor_serial",
  "fields": [41, 42],
  "case_insensitive": false,
  "nulls_distinct": true
}
AttributeRequiredDescription
custom_object_typeyesID of the Custom Object Type.
nameyesInternal name. Lowercase alphanumeric with underscores only; unique within the Custom Object Type.
typenounique (the default) or check.
fieldsfor uniqueIDs of the fields whose combined values must be unique: at least two, or one when case_insensitive is true or there's a condition. Omitted or [] for check. Responses list each field's id, url, name and schema_id.
case_insensitivenoFor unique: compare text, longtext and url fields without regard to case. Default: false.
nulls_distinctnoFor unique: when true, objects that leave any constrained field empty never conflict. Default: true.
conditionnoApply the constraint only to objects matching all of these predicates, e.g. [{"field": 43, "lookup": "isnull", "value": true}]. field is a field ID (responses show the brief field object); lookup is exact, n (does not equal, or is empty), in (value is a list), isnull (value is true or false), or gt, gte, lt or lte (integer, decimal, date and datetime fields). A value of {"field": <ID>} compares with another field of the same kind. Object fields can only be tested with isnull. Default: [].
rulefor checkPredicates, in the same form as condition, that every object (matching the condition, if any) must satisfy. A comparison passes when a value it compares is empty.
error_messagenoFor check: the error returned when an object breaks the rule. Default: a description of the rule.
descriptionnoA short description.

A check constraint names its fields in its rule instead:

{
  "custom_object_type": 9,
  "name": "end_after_start",
  "type": "check",
  "rule": [{"field": 45, "lookup": "gt", "value": {"field": 44}}],
  "error_message": "The end date must be after the start date."
}

Creating or changing a constraint returns 400 Bad Request if existing objects already violate it. Writes to custom objects that would violate a constraint also return 400 Bad Request.

Custom Objects

Once a Custom Object Type's schema is defined, create Custom Objects (instances) with a POST to /api/plugins/custom-objects/<slug>/, where <slug> is the slug of the Custom Object Type:

{
  "internal_id": 102,
  "hostname": "server-001",
  "cpu_cores": 8,
  "environment": "production",
  "device_list": [34, 1],
  "primary_device": 16
}

For select fields, pass the choice's value; for multiselect fields, a list of values. For non-polymorphic object and multiobject fields, pass the primary key (integer) of the referenced object - or a list of primary keys, for multiobject. For polymorphic fields, pass a dict identifying both the content type and the object (a list of them, for multiobject):

{
  "linked_resource": {"app_label": "dcim", "model": "device", "object_id": 7}
}

content_type_id may be used in place of app_label + model, and id may be used in place of object_id.

The response includes the created object with its assigned ID and standard metadata. Values are read back in a richer form than they are written:

  • select values are returned as {"value": ..., "label": ...}, and multiselect values as a list of them.
  • object and multiobject values are returned as brief representations of the referenced objects.
  • Polymorphic values are returned as {"_content_type": "<app_label>.<model>", "id": ..., "display": ...}. To write one back, replace _content_type with app_label and model, or with content_type_id.
{
  "id": 15,
  "url": "https://netbox/api/plugins/custom-objects/server/15/",
  "display": "server-001",
  "owner": null,
  "created": "2026-01-15T10:30:00.358032Z",
  "last_updated": "2026-01-15T10:30:00.382330Z",
  "tags": [],
  "cpu_cores": 8,
  "device_list": [
    {
      "id": 34,
      "url": "https://netbox/api/dcim/devices/34/",
      "display": "dev2",
      "name": "dev2",
      "description": ""
    },
    {
      "id": 1,
      "url": "https://netbox/api/dcim/devices/1/",
      "display": "dev3",
      "name": "dev3",
      "description": ""
    }
  ],
  "environment": {
    "value": "production",
    "label": "Production"
  },
  "hostname": "server-001",
  "internal_id": 102,
  "primary_device": {
    "id": 16,
    "url": "https://netbox/api/dcim/devices/16/",
    "display": "dev1",
    "name": "dev1",
    "description": ""
  }
}

display is the object's display name, and owner is NetBox's object owner. With ?brief=true, objects are returned as just id, url and display. As with core endpoints, ?fields= and ?omit= select which fields are returned.

Config context

For a Custom Object Type with config context support enabled, each object also includes local_context_data (writable) and config_context (read-only): the rendered context, as a Device or VM has. See Config Context for which source contexts apply. Rendering costs extra queries, so leave it out with ?omit=config_context when you don't need it.

If the type has a custom field named config_context, that field is returned instead of the rendered context.

Custom Validation

NetBox's CUSTOM_VALIDATORS setting is supported for Custom Objects. Use netbox_custom_objects.<cot-slug> as the key, where <cot-slug> is the slug of the Custom Object Type:

# configuration.py
CUSTOM_VALIDATORS = {
    "netbox_custom_objects.server": [
        {
            "hostname": {"min_length": 3, "max_length": 64},
            "cpu_cores": {"min": 1},
        }
    ]
}

Validators are enforced on both API writes and UI form submissions. Any violation raises an HTTP 400 error (API) or a form validation error (UI).

The key must use the Custom Object Type slug (e.g. server), not the type's name or its internal model name.

Linked Objects

Any NetBox object - whether a core object such as Device or Site, or a Custom Object - can be referenced by one or more Custom Objects via object or multiobject fields. To retrieve all Custom Objects that link to a given object, query the linked-objects endpoint:

GET /api/plugins/custom-objects/linked-objects/?object_type=<object_type>&object_id=<object_id>

Both query parameters are required:

ParameterDescription
object_typeTarget model in app_label.model form, e.g. dcim.device.
object_idPrimary key of the target object.

Example response:

{
    "count": 1,
    "results": [
        {
            "custom_object_type": {
                "id": 9,
                "url": "https://netbox/api/plugins/custom-objects/custom-object-types/9/",
                "name": "server",
                "slug": "server",
                "description": "Server inventory objects"
            },
            "field_name": "primary_device",
            "object": {
                "id": 15,
                "url": "https://netbox/api/plugins/custom-objects/server/15/",
                "display": "server-001",
                ...
            }
        }
    ]
}

object is the full representation of the custom object, as returned by its own endpoint. Results aren't paginated. A missing or invalid parameter returns 400 Bad Request, and a target object you can't view returns 404 Not Found.

OpenAPI schema

The Custom Object endpoints appear in NetBox's OpenAPI schema (/api/schema/) once, generically, with the Custom Object Type's slug as the custom_object_type path parameter:

  • /api/plugins/custom-objects/{custom_object_type}/
  • /api/plugins/custom-objects/{custom_object_type}/{id}/

The CustomObject schema lists the fields every custom object has (id, url, display, owner, tags, created, last_updated) and allows additional properties, since each type's custom fields are defined at runtime. Clients generated from the schema therefore treat custom fields as free-form properties. The schema doesn't describe each Custom Object Type's own fields; use the Custom Object Type Fields endpoint to discover them.

Browsable API

As with other NetBox objects, you can view the API output for Custom Objects in a browser by prepending /api/ to the URL - for example, /api/plugins/custom-objects/dhcp_scope/:

HTTP 200 OK
Allow: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1,
            "url": "https://netbox/api/plugins/custom-objects/dhcp_scope/1/",
            "display": "DHCP Scope 1",
            "owner": null,
            "created": "2026-01-15T10:30:00.358032Z",
            "last_updated": "2026-01-15T10:30:00.358032Z",
            "tags": [],
            "range": {
                "id": 1,
                "url": "https://netbox/api/ipam/ip-ranges/1/",
                "display": "192.168.0.1-100/24",
                "family": {
                    "value": 4,
                    "label": "IPv4"
                },
                "start_address": "192.168.0.1/24",
                "end_address": "192.168.0.100/24",
                "description": ""
            }
        }
    ]
}

Other Operations

GET, PUT, PATCH, and DELETE requests are supported on all of the above, using the detail URL for each object:

ResourceDetail URL
Custom Object Type/api/plugins/custom-objects/custom-object-types/<id>/
Custom Object Type Field/api/plugins/custom-objects/custom-object-type-fields/<id>/
Custom Object Type Constraint/api/plugins/custom-objects/custom-object-type-constraints/<id>/
Custom Object/api/plugins/custom-objects/<slug>/<id>/

Standard NetBox filter parameters (e.g. q=, tag=, created__gte=) work against the list endpoints. Each Custom Object Type's endpoint also has a filter for each of its fields; see Filtering Custom Objects.

The Custom Object Type and Custom Object Type Field list endpoints accept filters for their own attributes, for example ?slug=dhcp_scope or ?name=hostname. Fields can also be filtered by the type they belong to (?custom_object_type_id=9 or ?custom_object_type=dhcp_scope) and by field type (?type=integer).

Filtering Custom Objects

Each field of a Custom Object Type gets a filter on that type's endpoint, named after the field, unless the field's Filter logic is disabled. The select, multiselect, color, mac_address and multiobject filters can be repeated to match any of several values, e.g. ?environment=production&environment=staging; the others take a single value.

Field typeFilter
text, longtext, url?<field>= matches part of the value when filter logic is loose (the default), or the whole value when it's exact. Either way, the core NetBox lookup suffixes are available, e.g. ?<field>__isw= (starts with) or ?<field>__n= (does not equal).
json?<field>= matches part of the JSON text.
integer, decimal?<field>= matches the value exactly; suffixes such as __gte, __lt and __n are also available.
date, datetime?<field>= matches the value exactly.
boolean?<field>=true or false.
select?<field>=<value> matches the choice value.
multiselect?<field>=<value> matches objects whose selections include the value.
color, mac_address?<field>= matches the value exactly.
object?<field>=<id> or ?<field>_id=<id> matches the referenced object's ID.
multiobject?<field>=<id> matches objects that reference that ID.
polymorphic object / multiobjectOne filter per allowed type, named <field>_<app_label>_<model>, e.g. ?linked_resource_dcim_device=7.
array?<field>=a,b matches objects whose list includes every one of the comma-separated values; ?<field>__len= matches the number of items.
coordinates?<field>_latitude= and ?<field>_longitude=.

Bulk Operations

All four list endpoints (types, fields, constraints and each type's objects) accept bulk writes, the same as NetBox core endpoints. Send a list of objects, each identifying its target by id:

MethodBodyEffect
POST[{...}, {...}]Create several objects
PATCH[{"id": 1, "description": "new"}, ...]Partially update each listed object
PUT[{"id": 1, ...all fields...}, ...]Fully update each listed object
DELETE[{"id": 1}, {"id": 2}]Delete each listed object

Each request is applied atomically: if any listed object cannot be created, updated, or deleted, none of them are changed. Deleting a Custom Object Type drops its database table along with every object of that type.

Custom object endpoints don't support NetBox's ?background=true option for running bulk writes as a background job; requests that use it return 400 Bad Request.

Export Templates

A Custom Object list endpoint can render a NetBox export template instead of returning JSON, as core list endpoints do.

  1. Create an export template and add the Custom Object Type to its Object types.
  2. Request the type's list endpoint with ?export= set to the export template's name.

For example, with a Custom Object Type whose slug is dhcp_scope and an export template named Scopes CSV:

GET /api/plugins/custom-objects/dhcp_scope/?export=Scopes%20CSV&status=active

The template's queryset contains every object that matches the request's filters (here status=active) and that you have permission to view. Exports aren't paginated, so limit and offset have no effect. The response uses the template's MIME type and file settings.

The response is a 404 if no export template with that name is assigned to this Custom Object Type, or, on NetBox 4.6.1 and later, if you don't have permission to view the template.

On this page