POST /v1/join-keys
Create a join key: a reusable enrollment code that any number of machines can enroll with,
each joining as a new host with the key’s network, role, and tags. Enroll a machine by passing
the returned token to dnclient enroll -code.
The token is only returned by this request, so store it somewhere safe.
Returns ERR_LIMIT_EXCEEDED if the organization has reached its join key limit.
Token scope required: join-keys:create
Authorizations
Section titled “Authorizations ”Request Body required
Section titled “Request Body required ”object
Identifies the key, and names hosts that enroll without reporting a usable hostname. Must be a DNS label: lowercase letters, digits, and hyphens, not starting or ending with a hyphen. Must be unique within the organization.
Example
ci-runnerNetwork that hosts enrolled with this key join. Can’t be changed later.
Example
network-KAOWMXZHZWCVMGGFKM22XEGYLERole assigned to hosts enrolled with this key. Can’t be changed later.
Example
role-PZEDBXHCEXKAKJPZ6XOQTIAJA4Tags assigned to hosts enrolled with this key. Can’t be changed later.
Example
[ "env:ci"]Prefixes from which hosts enrolled with this key are assigned addresses. Each must exactly match the network’s IPv4 CIDR or IPv6 prefix. On a network with an IPv6 prefix, that prefix is always included even if omitted here, so list the IPv4 CIDR to also give enrolled hosts an IPv4 address. Can’t be changed later.
Example
[ "100.100.0.0/22"]When the key stops enrolling hosts. Must be in the future. Omit for a key that does not expire.
Example
2027-01-01T00:00:00ZExample
{ "name": "ci-runner", "networkID": "network-KAOWMXZHZWCVMGGFKM22XEGYLE", "roleID": "role-PZEDBXHCEXKAKJPZ6XOQTIAJA4", "tags": [ "env:ci" ], "autoAssignCIDRs": [ "100.100.0.0/22" ], "expiresAt": "2027-01-01T00:00:00Z"}Responses
Section titled “ Responses ”Successful operation
object
object
Example
dnjoin-P3RCTXN5LVFGBMJNYF2QHKWDOAExample
org-F63A24JGCLJV3ZEUTLCBISGETAIdentifies the key. Hosts that enroll without reporting a usable hostname are named after it, followed by a random suffix.
Example
ci-runnerNetwork that hosts enrolled with this key join.
Example
network-KAOWMXZHZWCVMGGFKM22XEGYLERole assigned to hosts enrolled with this key.
Example
role-PZEDBXHCEXKAKJPZ6XOQTIAJA4Tags assigned to hosts enrolled with this key.
Example
[ "env:ci"]Prefixes from which hosts enrolled with this key are assigned addresses. Includes the network’s IPv6 prefix whenever the network has one.
Example
[ "100.100.0.0/22", "fdef:c0:c0:1::/80"]When the key stops enrolling hosts. null means the key does not expire.
Example
2027-01-01T00:00:00ZExample
2026-10-29T15:00:00ZExample
2026-10-29T15:00:00ZThe token machines enroll with. Only returned when the key is created.
Example
dnjoin-P3RCTXN5LVFGBMJNYF2QHKWDOA-6YQKZ3VNB2XGJ4MEPLRT7WCSAHDUF5IO3QXBKZNYV2MJ4RLEHGTAExample
{ "data": { "id": "dnjoin-P3RCTXN5LVFGBMJNYF2QHKWDOA", "organizationID": "org-F63A24JGCLJV3ZEUTLCBISGETA", "name": "ci-runner", "networkID": "network-KAOWMXZHZWCVMGGFKM22XEGYLE", "roleID": "role-PZEDBXHCEXKAKJPZ6XOQTIAJA4", "tags": [ "env:ci" ], "autoAssignCIDRs": [ "100.100.0.0/22", "fdef:c0:c0:1::/80" ], "expiresAt": "2027-01-01T00:00:00Z", "createdAt": "2026-10-29T15:00:00Z", "modifiedAt": "2026-10-29T15:00:00Z", "token": "dnjoin-P3RCTXN5LVFGBMJNYF2QHKWDOA-6YQKZ3VNB2XGJ4MEPLRT7WCSAHDUF5IO3QXBKZNYV2MJ4RLEHGTA" }}Validation error
object
object
A static name for the error type
A short human readable description of the error
Describes the variable missing or malformed
The query parameter the error relates to, such as filter.targetType
Machine-readable details about the error. ERR_LIMIT_EXCEEDED errors carry limit and limitName.
object
The maximum number of resources allowed
The kind of resource the limit applies to
Examples
A join key already exists with the name.
{ "errors": [ { "code": "ERR_DUPLICATE_VALUE", "message": "value already exists", "path": "name" } ]}The name is not a DNS label.
{ "errors": [ { "code": "ERR_INVALID_VALUE", "message": "must contain only lowercase letters, digits, and hyphens, and must not start or end with a hyphen", "path": "name" } ]}`expiresAt` is not in the future.
{ "errors": [ { "code": "ERR_INVALID_VALUE", "message": "must be in the future", "path": "expiresAt" } ]}The network or role does not exist. Not returned on update.
{ "errors": [ { "code": "ERR_INVALID_REFERENCE", "message": "referenced value is invalid (perhaps it does not exist?)", "path": "networkID" } ]}An `autoAssignCIDRs` entry is an address rather than a CIDR prefix. Not returned on update.
{ "errors": [ { "code": "ERR_INVALID_VALUE", "message": "must be a CIDR prefix, not an address", "path": "autoAssignCIDRs[0]" } ]}An `autoAssignCIDRs` entry isn't exactly the network's IPv4 CIDR or IPv6 prefix. Not returned on update.
{ "errors": [ { "code": "ERR_OUT_OF_RANGE", "message": "CIDR prefix does not match the network's IPv4 CIDR", "path": "autoAssignCIDRs[0]" } ]}The API key is missing, invalid or expired.
object
object
A static name for the error type
A short human readable description of the error
Describes the variable missing or malformed
The query parameter the error relates to, such as filter.targetType
Machine-readable details about the error. ERR_LIMIT_EXCEEDED errors carry limit and limitName.
object
The maximum number of resources allowed
The kind of resource the limit applies to
Example
{ "errors": [ { "code": "ERR_UNAUTHORIZED", "message": "unauthorized" } ]}The API key lacks a required scope.
object
object
A static name for the error type
A short human readable description of the error
Describes the variable missing or malformed
The query parameter the error relates to, such as filter.targetType
Machine-readable details about the error. ERR_LIMIT_EXCEEDED errors carry limit and limitName.
object
The maximum number of resources allowed
The kind of resource the limit applies to
Examples
The API key lacks a required scope.
{ "errors": [ { "code": "ERR_FORBIDDEN", "message": "api key must support the following scopes: hosts:read" } ]}The organization has exceeded its API request rate limit. Retry the request after a short delay.
object
object
A static name for the error type
A short human readable description of the error
Describes the variable missing or malformed
The query parameter the error relates to, such as filter.targetType
Machine-readable details about the error. ERR_LIMIT_EXCEEDED errors carry limit and limitName.
object
The maximum number of resources allowed
The kind of resource the limit applies to
Example
{ "errors": [ { "code": "ERR_TOO_MANY_REQUESTS", "message": "too many requests" } ]}