Devices within a tailnet can be set up as subnet routers.
A subnet router acts as a gateway, relaying traffic from your Tailscale network onto your physical subnet.
Setting up subnet routers exposes routes to other devices in the tailnet.
Learn more about [subnet routers](https://tailscale.com/kb/1019).
A device can act as a subnet router if its subnet routes are both advertised and enabled.
This is a two-step process, but the steps can occur in any order:
- The device that intends to act as a subnet router exposes its routes by **advertising** them.
This is done in the Tailscale command-line interface.
- The tailnet admin must approve the routes by **enabling** them.
This is done in the [**Machines**](https://login.tailscale.com/admin/machines) page of the Tailscale admin console
or [via the API](#set-device-routes).
If a device has advertised routes, they are not exposed to traffic until they are enabled by the tailnet admin.
Conversely, if a tailnet admin pre-approves certain routes by enabling them, they are not available for routing until the device in question has advertised them.
The API exposes two methods for dealing with subnet routes:
- Get routes: [`GET /api/v2/device/{deviceID}/routes`](#get-device-routes) to fetch lists of advertised and enabled routes for a device
- Set routes: [`POST /api/v2/device/{deviceID}/routes`](#set-device-routes) to set enabled routes for a device
## Get device
```http
GET /api/v2/device/{deviceid}
```
Retrieve the details for the specified device.
This returns a JSON `device` object listing device attributes.
### Parameters
#### `deviceid` (required in URL path)
The ID of the device.
#### `fields` (optional in query string)
Controls whether the response returns **all** object fields or only a predefined subset of fields.
Currently, there are two supported options:
- **`all`:** return all object fields in the response
- **`default`:** return all object fields **except**:
-`enabledRoutes`
-`advertisedRoutes`
-`clientConnectivity` (which contains the following fields: `mappingVariesByDestIP`, `derp`, `endpoints`, `latency`, and `clientSupports`)
This call marks a device as authorized or revokes its authorization for tailnets where device authorization is required, according to the `authorized` field in the payload.
This returns a successful 2xx response with an empty JSON object in the response body.
### Parameters
#### `deviceid` (required in URL path)
The ID of the device.
#### `authorized` (required in `POST` body)
Specify whether the device is authorized. False to deauthorize an authorized device, and true to authorize a new device or to re-authorize a previously deauthorized device.
The response is 2xx on success. The response body is currently an empty JSON object.
## Tags
## Update device tags
```http
POST /api/v2/device/{deviceID}/tags
```
Update the tags set on a device.
Tags let you assign an identity to a device that is separate from human users, and use that identity as part of an ACL to restrict access.
Tags are similar to role accounts, but more flexible.
Tags are created in the tailnet policy file by defining the tag and an owner of the tag.
Once a device is tagged, the tag is the owner of that device.
A single node can have multiple tags assigned.
Consult the policy file for your tailnet in the [admin console](https://login.tailscale.com/admin/acls) for the list of tags that have been created for your tailnet.
Learn more about [tags](https://tailscale.com/kb/1068/).
This returns a 2xx code if successful, with an empty JSON object in the response body.
The response is 2xx on success. The response body is currently an empty JSON object.
If the tags supplied in the `POST` call do not exist in the tailnet policy file, the response is '400 Bad Request':
```jsonc
{
"message": "requested tags [tag:madeup tag:wrongexample] are invalid or not permitted"
}
```
## Keys
## Update device key
```http
POST /api/v2/device/{deviceID}/key
```
Update properties of the device key.
### Parameters
#### `deviceid` (required in URL path)
The ID of the device.
#### `keyExpiryDisabled` (optional in `POST` body)
Disable or enable the expiry of the device's node key.
When a device is added to a tailnet, its key expiry is set according to the tailnet's [key expiry](https://tailscale.com/kb/1028/) setting.
If the key is not refreshed and expires, the device can no longer communicate with other devices in the tailnet.
Set `"keyExpiryDisabled": true` to disable key expiry for the device and allow it to rejoin the tailnet (for example to access an accidentally expired device).
You can then call this method again with `"keyExpiryDisabled": false` to re-enable expiry.
```jsonc
{
"keyExpiryDisabled": true
}
```
- If `true`, disable the device's key expiry.
The original key expiry time is still maintained.
Upon re-enabling, the key will expire at that original time.
- If `false`, enable the device's key expiry.
Sets the key to expire at the original expiry time prior to disabling.
The key may already have expired. In that case, the device must be re-authenticated.
- Empty value will not change the key expiry.
This returns a 2xx code on success, with an empty JSON object in the response body.
The response is 2xx on success. The response body is currently an empty JSON object.
## IP Addresses
## Set device IPv4 address
```http
POST /api/v2/device/{deviceID}/ip
```
Set the Tailscale IPv4 address of the device.
### Parameters
#### `deviceid` (required in URL path)
The ID of the device.
#### `ipv4` (optional in `POST` body)
Provide a new IPv4 address for the device.
When a device is added to a tailnet, its Tailscale IPv4 address is set at random either from the CGNAT range, or a subset of the CGNAT range specified by an [ip pool](https://tailscale.com/kb/1304/ip-pool).
This endpoint can be used to replace the existing IPv4 address with a specific value.
```jsonc
{
"ipv4": "100.80.0.1"
}
```
This action will break any existing connections to this machine.
You will need to reconnect to this machine using the new IP address.
You may also need to flush your DNS cache.
This returns a 2xx code on success, with an empty JSON object in the response body.
The response is 200 on success. The response body is a JSON object containing all the posture attributes assigned to the node. Attribute values can be strings, numbers or booleans.
```json
{
"attributes": {
"custom:myScore": 87,
"custom:diskEncryption": true,
"custom:myAttribute": "my_value",
"node:os": "linux",
"node:osVersion": "5.19.0-42-generic",
"node:tsReleaseTrack": "stable",
"node:tsVersion": "1.40.0",
"node:tsAutoUpdate": false
}
}
```
## Set custom device posture attributes
```
POST /api/v2/device/{deviceID}/attributes/{attributeKey}
```
Create or update a custom posture attribute on the specified device. User-managed attributes must be in the `custom` namespace, which is indicated by prefixing the attribute key with `custom:`.
Custom device posture attributes are available for the Personal and Enterprise plans.
### Parameters
#### `deviceID` (required in URL path)
The ID of the device on which to set the custom posture attribute.
#### `attributeKey` (required in URL path)
The name of the posture attribute to set. This must be prefixed with `custom:`.
Keys have a maximum length of 50 characters including the namespace, and can only contain letters, numbers, underscores, and colon.
Keys are case-sensitive. Keys must be unique, but are checked for uniqueness in a case-insensitive manner. For example, `custom:MyAttribute` and `custom:myattribute` cannot both be set within a single tailnet.
All values for a given key need to be of the same type, which is determined when the first value is written for a given key. For example, `custom:myattribute` cannot have a numeric value (`87`) for one node and a string value (`"78"`) for another node within the same tailnet.
### Posture attribute `value` (required in POST body)
```json
{
"value": "foo"
}
```
A value can be either a string, number or boolean.
A string value can have a maximum length of 50 characters, and can only contain letters, numbers, underscores, and periods.
A number value is an integer and must be a JSON safe number (up to 2^53 - 1).
Delete a posture attribute from the specified device. This is only applicable to user-managed posture attributes in the `custom` namespace, which is indicated by prefixing the attribute key with `custom:`.
<PricingPlanNotefeature="Custom device posture attributes"verb="are"plan="the Personal and Enterprise plans"/>
### Parameters
#### `deviceID` (required in URL path)
The ID of the device from which to delete the posture attribute.
#### `attributeKey` (required in URL path)
The name of the posture attribute to delete. This must be prefixed with `custom:`.
Keys have a maximum length of 50 characters including the namespace, and can only contain letters, numbers, underscores, and a delimiting colon.
#### List of invite requests (required in `POST` body)
Each invite request is an object with the following optional fields:
- **`multiUse`:** (Optional) Specify whether the invite can be accepted more than once. When set to `true`, it results in an invite that can be accepted up to 1,000 times.
- **`allowExitNode`:** (Optional) Specify whether the invited user can use the device as an exit node when it advertises as one.
- **`email`:** (Optional) Specify the email to send the created invite. If not set, the endpoint generates and returns an invite URL (but doesn't send it out).
### Request example
```sh
curl -X POST "https://api.tailscale.com/api/v2/device/11055/device-invites" \