Browse Source

publicapi: include device and user invites API documentation (#12168)

This change includes the device and user invites API docs in the
new publicapi documentation structure.

Updates tailscale/corp#19526

Signed-off-by: Charlotte Brandhorst-Satzkorn <[email protected]>
Charlotte Brandhorst-Satzkorn 1 year ago
parent
commit
c56e0c4934
5 changed files with 599 additions and 0 deletions
  1. 112 0
      publicapi/device.md
  2. 221 0
      publicapi/deviceinvites.md
  3. 19 0
      publicapi/overview.md
  4. 103 0
      publicapi/tailnet.md
  5. 144 0
      publicapi/userinvites.md

+ 112 - 0
publicapi/device.md

@@ -208,6 +208,9 @@ You can also [list all devices in the tailnet](#list-tailnet-devices) to get the
   - Get device posture attributes: [`GET /api/v2/device/{deviceID}/attributes`](#get-device-posture-attributes)
   - Set custom device posture attributes: [`POST /api/v2/device/{deviceID}/attributes/{attributeKey}`](#set-device-posture-attributes)
   - Delete custom device posture attributes: [`DELETE /api/v2/device/{deviceID}/attributes/{attributeKey}`](#delete-custom-device-posture-attributes)
+- [**Device invites**](#invites-to-a-device)
+  - List device invites: [`GET /api/v2/device/{deviceID}/device-invites`](#list-device-invites)
+  - Create device invites: [`POST /api/v2/device/{deviceID}/device-invites`](#create-device-invites)
 
 ### Subnet routes
 
@@ -793,3 +796,112 @@ curl -X DELETE "https://api.tailscale.com/api/v2/device/11055/attributes/custom:
 ### Response
 
 The response is 2xx on success. The response body is currently an empty JSON object.
+
+## Invites to a device
+
+The device sharing invite methods let you create and list [invites to share a device](https://tailscale.com/kb/1084/sharing).
+
+## List device invites
+
+```http
+GET /api/v2/device/{deviceID}/device-invites
+```
+
+List all share invites for a device.
+
+### Parameters
+
+#### `deviceID` (required in URL path)
+
+The ID of the device.
+
+### Request example
+
+```sh
+curl -X GET "https://api.tailscale.com/api/v2/device/11055/device-invites" \
+-u "tskey-api-xxxxx:"
+```
+
+### Response
+
+```jsonc
+[
+  {
+    "id": "12345",
+    "created": "2024-05-08T20:19:51.777861756Z",
+    "tailnetId": 59954,
+    "deviceId": 11055,
+    "sharerId": 22011,
+    "allowExitNode": true,
+    "email": "[email protected]",
+    "lastEmailSentAt": "2024-05-08T20:19:51.777861756Z",
+    "inviteUrl": "https://login.tailscale.com/admin/invite/<code>",
+    "accepted": false
+  },
+  {
+    "id": "12346",
+    "created": "2024-04-03T21:38:49.333829261Z",
+    "tailnetId": 59954,
+    "deviceId": 11055,
+    "sharerId": 22012,
+    "inviteUrl": "https://login.tailscale.com/admin/invite/<code>",
+    "accepted": true,
+    "acceptedBy": {
+      "id": 33223,
+      "loginName": "[email protected]",
+      "profilePicUrl": ""
+    }
+  }
+]
+```
+
+## Create device invites
+
+```http
+POST /api/v2/device/{deviceID}/device-invites
+```
+
+Create new share invites for a device.
+
+### Parameters
+
+#### `deviceID` (required in URL path)
+
+The ID of the device.
+
+#### 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" \
+-u "tskey-api-xxxxx:" \
+-H "Content-Type: application/json" \
+--data-binary '[{"multiUse": true, "allowExitNode": true, "email":"[email protected]"}]'
+```
+
+### Response
+
+```jsonc
+[
+  {
+    "id": "12347",
+    "created": "2024-05-08T20:29:45.842358533Z",
+    "tailnetId": 59954,
+    "deviceId": 11055,
+    "sharerId": 22012,
+    "multiUse": true,
+    "allowExitNode": true,
+    "email": "[email protected]",
+    "lastEmailSentAt": "2024-05-08T20:29:45.842358533Z",
+    "inviteUrl": "https://login.tailscale.com/admin/invite/<code>",
+    "accepted": false
+  }
+]
+```

+ 221 - 0
publicapi/deviceinvites.md

@@ -0,0 +1,221 @@
+# Device invites
+
+A device invite is an invitation that shares a device with an external user (a user not in the device's tailnet).
+
+Each device invite has a unique ID that is used to identify the invite in API calls.
+You can find all device invite IDs for a particular device by [listing all device invites for a device](#list-device-invites).
+
+### Attributes
+
+```jsonc
+{
+  // id (strings) is the unique identifier for the invite.
+  // Supply this value wherever {deviceInviteId} is indicated in the endpoint.
+  "id": "12346",
+
+  // created is the creation time of the invite.
+  "created": "2024-04-03T21:38:49.333829261Z",
+
+  // tailnetId is the ID of the tailnet to which the shared device belongs.
+  "tailnetId": 59954,
+
+  // deviceId is the ID of the device being shared.
+  "deviceId": 11055,
+
+  // sharerId is the ID of the user who created the share invite.
+  "sharerId": 22012,
+
+  // multiUse specifies whether this device invite can be accepted more than
+  // once.
+  "multiUse": false,
+
+  // allowExitNode specifies whether the invited user is able to use the
+  // device as an exit node when the device is advertising as one.
+  "allowExitNode": true,
+
+  // email is the email to which the invite was sent.
+  // If empty, the invite was not emailed to anyone, but the inviteUrl can be
+  // shared manually.
+  "email": "[email protected]",
+
+  // lastEmailSentAt is the last time the invite was attempted to be sent to
+  // Email. Only ever set if Email is not empty.
+  "lastEmailSentAt": "2024-04-03T21:38:49.333829261Z",
+
+  // inviteUrl is the link to accept the invite.
+  // Anyone with this link can accept the invite.
+  // It is not restricted to the person to which the invite was emailed.
+  "inviteUrl": "https://login.tailscale.com/admin/invite/<code>",
+
+  // accepted is true when share invite has been accepted.
+  "accepted": true,
+
+  // acceptedBy is set when the invite has been accepted.
+  // It holds information about the user who accepted the share invite.
+  "acceptedBy": {
+    // id is the ID of the user who accepted the share invite.
+    "id": 33223,
+
+    // loginName is the login name of the user who accepted the share invite.
+    "loginName": "[email protected]",
+
+    // profilePicUrl is optionally the profile pic URL for the user who accepted
+    // the share invite.
+    "profilePicUrl": ""
+  }
+}
+```
+
+# API
+
+**[Device invites](#device-invites)**
+
+- Get device invite: [`GET /api/v2/device-invites/{deviceInviteId}`](#get-device-invite)
+- Delete device invite: [`DELETE /api/v2/device-invites/{deviceInviteId}`](#delete-device-invite)
+- Resend device invite (by email): [`POST /api/v2/device-invites/{deviceInviteId}/resend`](#resend-device-invite)
+- Accept device invite [`POST /api/v2/device-invites/-/accept`](#accept-device-invite)
+
+## Get device invite
+
+```http
+GET /api/v2/device-invites/{deviceInviteId}
+```
+
+Retrieve the specified device invite.
+
+### Parameters
+
+#### `deviceInviteId` (required in URL path)
+
+The ID of the device share invite.
+
+### Request example
+
+```sh
+curl "https://api.tailscale.com/api/v2/device-invites/12346" \
+  -u "tskey-api-xxxxx:"
+```
+
+### Response
+
+```jsonc
+{
+  "id": "12346",
+  "created": "2024-04-03T21:38:49.333829261Z",
+  "tailnetId": 59954,
+  "deviceId": 11055,
+  "sharerId": 22012,
+  "multiUse": true,
+  "allowExitNode": true,
+  "email": "[email protected]",
+  "lastEmailSentAt": "2024-04-03T21:38:49.333829261Z",
+  "inviteUrl": "https://login.tailscale.com/admin/invite/<code>",
+  "accepted": false
+}
+```
+
+## Delete device invite
+
+```http
+DELETE /api/v2/device-invites/{deviceInviteId}
+```
+
+Delete the specified device invite.
+
+### Parameters
+
+#### `deviceInviteId` (required in URL path)
+
+The ID of the device share invite.
+
+### Request example
+
+```sh
+curl -X DELETE "https://api.tailscale.com/api/v2/device-invites/12346" \
+  -u "tskey-api-xxxxx:"
+```
+
+### Response
+
+The response is 2xx on success. The response body is an empty JSON object.
+
+## Resend device invite
+
+```http
+POST /api/v2/device-invites/{deviceInviteId}/resend
+```
+
+Resend the specified device invite by email. You can only use this if the specified invite was originally created with an email specified. Refer to [creating device invites for a device](#create-device-invites).
+
+Note: Invite resends are rate limited to one per minute.
+
+### Parameters
+
+#### `deviceInviteId` (required in URL path)
+
+The ID of the device share invite.
+
+### Request example
+
+```sh
+curl -X POST "https://api.tailscale.com/api/v2/device-invites/12346/resend" \
+  -u "tskey-api-xxxxx:"
+```
+
+### Response
+
+The response is 2xx on success. The response body is an empty JSON object.
+
+## Accept device invite
+
+```http
+POST /api/v2/device-invites/-/accept
+```
+
+Resend the specified device invite by email. This can only be used if the specified invite was originally created with an email specified.
+See [creating device invites for a device](#create-device-invites).
+
+Note that invite resends are rate limited to once per minute.
+
+### Parameters
+
+#### `invite` (required in `POST` body)
+
+The URL of the invite (in the form "https://login.tailscale.com/admin/invite/{code}") or the "{code}" component of the URL.
+
+### Request example
+
+```sh
+curl -X POST "https://api.tailscale.com/api/v2/device-invites/-/accept" \
+  -u "tskey-api-xxxxx:" \
+  -H "Content-Type: application/json" \
+  --data-binary '[{"invite": "https://login.tailscale.com/admin/invite/xxxxxx"}]'
+```
+
+### Response
+
+```jsonc
+{
+  "device": {
+    "id": "11055",
+    "os": "iOS",
+    "name": "my-phone",
+    "fqdn": "my-phone.something.ts.net",
+    "ipv4": "100.x.y.z",
+    "ipv6": "fd7a:115c:x::y:z",
+    "includeExitNode": false
+  },
+  "sharer": {
+    "id": "22012",
+    "displayName": "Some User",
+    "loginName": "[email protected]",
+    "profilePicURL": ""
+  },
+  "acceptedBy": {
+    "id": "33233",
+    "displayName": "Another User",
+    "loginName": "[email protected]",
+    "profilePicURL": ""
+  }
+}
+```

+ 19 - 0
publicapi/overview.md

@@ -68,6 +68,9 @@ The Tailscale API does not currently support pagination. All results are returne
   - Get device posture attributes: [`GET /api/v2/device/{deviceID}/attributes`](./device.md#get-device-posture-attributes)
   - Set custom device posture attributes: [`POST /api/v2/device/{deviceID}/attributes/{attributeKey}`](./device.md#set-device-posture-attributes)
   - Delete custom device posture attributes: [`DELETE /api/v2/device/{deviceID}/attributes/{attributeKey}`](./device.md#delete-custom-device-posture-attributes)
+- [**Device invites**](./device.md#invites-to-a-device)
+  - List device invites: [`GET /api/v2/device/{deviceID}/device-invites`](./device.md#list-device-invites)
+  - Create device invites: [`POST /api/v2/device/{deviceID}/device-invites`](./device.md#create-device-invites)
 
 **[Tailnet](./tailnet.md#tailnet)**
 
@@ -97,3 +100,19 @@ The Tailscale API does not currently support pagination. All results are returne
     - Get split DNS: [`GET /api/v2/tailnet/{tailnet}/dns/split-dns`](./tailnet.md#get-split-dns)
     - Update split DNS: [`PATCH /api/v2/tailnet/{tailnet}/dns/split-dns`](./tailnet.md#update-split-dns)
     - Set split DNS: [`PUT /api/v2/tailnet/{tailnet}/dns/split-dns`](./tailnet.md#set-split-dns)
+- [**User invites**](./tailnet.md#tailnet-user-invites)
+  - List user invites: [`GET /api/v2/tailnet/{tailnet}/user-invites`](./tailnet.md#list-user-invites)
+  - Create user invites: [`POST /api/v2/tailnet/{tailnet}/user-invites`](./tailnet.md#create-user-invites)
+
+**[User invites](./userinvites.md#user-invites)**
+
+- Get user invite: [`GET /api/v2/user-invites/{userInviteId}`](./userinvites.md#get-user-invite)
+- Delete user invite: [`DELETE /api/v2/user-invites/{userInviteId}`](./userinvites.md#delete-user-invite)
+- Resend user invite (by email): [`POST /api/v2/user-invites/{userInviteId}/resend`](#resend-user-invite)
+
+**[Device invites](./deviceinvites.md#device-invites)**
+
+- Get device invite: [`GET /api/v2/device-invites/{deviceInviteId}`](./deviceinvites.md#get-device-invite)
+- Delete device invite: [`DELETE /api/v2/device-invites/{deviceInviteId}`](./deviceinvites.md#delete-device-invite)
+- Resend device invite (by email): [`POST /api/v2/device-invites/{deviceInviteId}/resend`](./deviceinvites.md#resend-device-invite)
+- Accept device invite [`POST /api/v2/device-invites/-/accept`](#accept-device-invite)

+ 103 - 0
publicapi/tailnet.md

@@ -52,6 +52,9 @@ When specifying a tailnet in the API, you can:
     - Get split DNS: [`GET /api/v2/tailnet/{tailnet}/dns/split-dns`](#get-split-dns)
     - Update split DNS: [`PATCH /api/v2/tailnet/{tailnet}/dns/split-dns`](#update-split-dns)
     - Set split DNS: [`PUT /api/v2/tailnet/{tailnet}/dns/split-dns`](#set-split-dns)
+- [**User invites**](#tailnet-user-invites)
+  - List user invites: [`GET /api/v2/tailnet/{tailnet}/user-invites`](#list-user-invites)
+  - Create user invites: [`POST /api/v2/tailnet/{tailnet}/user-invites`](#create-user-invites)
 
 ## Policy File
 
@@ -1316,3 +1319,103 @@ The response is a JSON object containing the updated map of split DNS settings.
 ```jsonc
 {}
 ```
+
+## Tailnet user invites
+
+The tailnet user invite methods let you create and list [invites](https://tailscale.com/kb/1371/invite-users).
+
+## List user invites
+
+```http
+GET /api/v2/tailnet/{tailnet}/user-invites
+```
+
+List all user invites that haven't been accepted.
+
+### Parameters
+
+#### `tailnet` (required in URL path)
+
+The tailnet organization name.
+
+### Request example
+
+```sh
+curl -X GET "https://api.tailscale.com/api/v2/tailnet/example.com/user-invites" \
+-u "tskey-api-xxxxx:"
+```
+
+### Response
+
+```jsonc
+[
+  {
+    "id": "29214",
+    "role": "member",
+    "tailnetId": 12345,
+    "inviterId": 34567,
+    "email": "[email protected]",
+    "lastEmailSentAt": "2024-05-09T16:13:16.084568545Z",
+    "inviteUrl": "https://login.tailscale.com/uinv/<code>"
+  },
+  {
+    "id": "29215",
+    "role": "admin",
+    "tailnetId": 12345,
+    "inviterId": 34567,
+    "inviteUrl": "https://login.tailscale.com/uinv/<code>"
+  }
+]
+```
+
+## Create user invites
+
+```http
+POST /api/v2/tailnet/{tailnet}/user-invites
+```
+
+Create new user invites to join the tailnet.
+
+### Parameters
+
+#### `tailnet` (required in URL path)
+
+The tailnet organization name.
+
+#### List of invite requests (required in `POST` body)
+
+Each invite request is an object with the following optional fields:
+
+- **`role`:** (Optional) Specify a [user role](https://tailscale.com/kb/1138/user-roles) to assign the invited user. Defaults to the `"member"` role. Valid options are:
+  - `"member"`: Assign the Member role.
+  - `"admin"`: Assign the Admin role.
+  - `"it-admin"`: Assign the IT admin role.
+  - `"network-admin"`: Assign the Network admin role.
+  - `"billing-admin"`: Assign the Billing admin role.
+  - `"auditor"`: Assign the Auditor role.
+- **`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/tailnet/example.com/user-invites" \
+-u "tskey-api-xxxxx:" \
+-H "Content-Type: application/json" \
+--data-binary '[{"role": "admin", "email":"[email protected]"}]'
+```
+
+### Response
+
+```jsonc
+[
+  {
+    "id": "29214",
+    "role": "admin",
+    "tailnetId": 12345,
+    "inviterId": 34567,
+    "email": "[email protected]",
+    "lastEmailSentAt": "2024-05-09T16:23:26.91778771Z",
+    "inviteUrl": "https://login.tailscale.com/uinv/<code>"
+  }
+]
+```

+ 144 - 0
publicapi/userinvites.md

@@ -0,0 +1,144 @@
+# User invites
+
+A user invite is an active invitation that lets a user join a tailnet with a pre-assigned [user role](https://tailscale.com/kb/1138/user-roles).
+
+Each user invite has a unique ID that is used to identify the invite in API calls.
+You can find all user invite IDs for a particular tailnet by [listing user invites](#list-user-invites).
+
+### Attributes
+
+```jsonc
+{
+  // id (string) is the unique identifier for the invite.
+  // Supply this value wherever {userInviteId} is indicated in the endpoint.
+  "id": "12346",
+
+  // role is the tailnet user role to assign to the invited user upon accepting
+  // the invite. Value options are "member", "admin", "it-admin", "network-admin",
+  // "billing-admin", and "auditor".
+  "role": "admin",
+
+  // tailnetId is the ID of the tailnet to which the user was invited.
+  "tailnetId": 59954,
+
+  // inviterId is the ID of the user who created the invite.
+  "inviterId": 22012,
+
+  // email is the email to which the invite was sent.
+  // If empty, the invite was not emailed to anyone, but the inviteUrl can be
+  // shared manually.
+  "email": "[email protected]",
+
+  // lastEmailSentAt is the last time the invite was attempted to be sent to
+  // Email. Only ever set if `email` is not empty.
+  "lastEmailSentAt": "2024-04-03T21:38:49.333829261Z",
+
+  // inviteUrl is included when `email` is not part of the tailnet's domain,
+  // or when `email` is empty. It is the link to accept the invite.
+  //
+  // When included, anyone with this link can accept the invite.
+  // It is not restricted to the person to which the invite was emailed.
+  //
+  // When `email` is part of the tailnet's domain (has the same @domain.com
+  // suffix as the tailnet), the user can join the tailnet automatically by
+  // logging in with their domain email at https://login.tailscale.com/start.
+  // They'll be assigned the specified `role` upon signing in for the first
+  // time.
+  "inviteUrl": "https://login.tailscale.com/admin/invite/<code>"
+}
+```
+
+# API
+
+**[User invites](#user-invites)**
+
+- Get user invite: [`GET /api/v2/user-invites/{userInviteId}`](#get-user-invite)
+- Delete user invite: [`DELETE /api/v2/user-invites/{userInviteId}`](#delete-user-invite)
+- Resend user invite (by email): [`POST /api/v2/user-invites/{userInviteId}/resend`](#resend-user-invite)
+
+## Get user invite
+
+```http
+GET /api/v2/user-invites/{userInviteId}
+```
+
+Retrieve the specified user invite.
+
+### Parameters
+
+#### `userInviteId` (required in URL path)
+
+The ID of the user invite.
+
+### Request example
+
+```sh
+curl "https://api.tailscale.com/api/v2/user-invites/29214" \
+  -u "tskey-api-xxxxx:"
+```
+
+### Response
+
+```jsonc
+{
+  "id": "29214",
+  "role": "admin",
+  "tailnetId": 12345,
+  "inviterId": 34567,
+  "email": "[email protected]",
+  "lastEmailSentAt": "2024-05-09T16:23:26.91778771Z",
+  "inviteUrl": "https://login.tailscale.com/uinv/<code>"
+}
+```
+
+## Delete user invite
+
+```http
+DELETE /api/v2/user-invites/{userInviteId}
+```
+
+Delete the specified user invite.
+
+### Parameters
+
+#### `userInviteId` (required in URL path)
+
+The ID of the user invite.
+
+### Request example
+
+```sh
+curl -X DELETE "https://api.tailscale.com/api/v2/user-invites/29214" \
+  -u "tskey-api-xxxxx:"
+```
+
+### Response
+
+The response is 2xx on success. The response body is an empty JSON object.
+
+## Resend user invite
+
+```http
+POST /api/v2/user-invites/{userInviteId}/resend
+```
+
+Resend the specified user invite by email. You can only use this if the specified invite was originally created with an email specified. Refer to [creating user invites for a tailnet](#create-user-invites).
+
+Note: Invite resends are rate limited to one per minute.
+
+### Parameters
+
+#### `userInviteId` (required in URL path)
+
+The ID of the user invite.
+
+### Request example
+
+```sh
+curl -X POST "https://api.tailscale.com/api/v2/user-invites/29214/resend" \
+  -u "tskey-api-xxxxx:"
+```
+
+### Response
+
+The response is 2xx on success. The response body is an empty JSON object.