---
title: Create MFA User Device (PingID Desktop)
component: pingone-api
page_id: pingone-api:mfa:users/mfa-devices/create-mfa-user-device-desktop
canonical_url: https://developer.pingidentity.com/pingone-api/mfa/users/mfa-devices/create-mfa-user-device-desktop.html
section_ids:
  headers: Headers
  body: Body
  example-request: Example Request
  example-response: Example Response
---

# Create MFA User Device (PingID Desktop)

##

   

```none
POST {{apiPath}}/environments/{{envID}}/users/{{userID}}/devices
```

The creation and pairing of a PingID Desktop device involves a sequence of requests and responses, including interaction with the Desktop API

This example shows the first step in this process, sending a POST request to the `devices` endpoint:

`POST {{apiPath}}/environments/{{envID}}/users/{{userID}}/devices`

The `type` parameter is set to PINGID\_DESKTOP\_GEN2.

For this request, the body must also contain the `status` parameter, which ordinarily is optional, but here must be set to `ACTIVATION_REQUIRED`.

This example also includes the optional but recommended parameter `policy.id`.

When creating a device for authentication with the PingID Desktop application, the relying party ID is taken by default from the relevant MFA policy. However, in the request to create the device, you have the option of including the [`rp` object](../mfa-devices.html#pingid-desktop-device-properties) in the body of the request in order to override the value from the MfA policy with a different domain.

> **Collapse: Request Model**
>
> | Property    | Type   | Required? |
> | ----------- | ------ | --------- |
> | `policy.id` | String | Optional  |
> | `status`    | String | Required  |
> | `type`      | String | Required  |
>
> Refer to the [MFA devices data model](../mfa-devices.html#device-properties) for full property descriptions.

The response from the PingOne server contains a field called `pingIdDesktopCredentialCreationOptions`, which consists of a signed JWT.

After the JWT is received, you must send it to the Desktop API Register endpoint `http://localhost:9410/register`. The body of that request should just be the JWT that you received, sent as plain text. The request must also include the header Content-Type set to `application/jwt` and the header Origin set to the Relying Party ID you specified in the relevant MFA policy, for example, `https://app.pingone.eu`

The response from the desktop agent will contain an attestation JWT, which must be used in [the request to activate](activate-mfa-user-device-desktop.html) the PingID Desktop device.

### Headers

Authorization      Bearer {{accessToken}}

Content-Type      application/json

### Body

raw ( application/json )

```json
{
    "type": "PINGID_DESKTOP_GEN2",
    "status": "ACTIVATION_REQUIRED",
    "policy": {
        "id": "{{deviceAuthenticationPolicyID}}"
    }
}
```

##

### Example Request

* cURL

* C#

* Go

* HTTP

* Java

* jQuery

* NodeJS

* Python

* PHP

* Ruby

* Swift

```shell
curl --location --globoff '{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{accessToken}}' \
--data '{
    "type": "PINGID_DESKTOP_GEN2",
    "status": "ACTIVATION_REQUIRED",
    "policy": {
        "id": "{{deviceAuthenticationPolicyID}}"
    }
}'
```

```csharp
var options = new RestClientOptions("{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices")
{
  MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("", Method.Post);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Bearer {{accessToken}}");
var body = @"{" + "\n" +
@"    ""type"": ""PINGID_DESKTOP_GEN2""," + "\n" +
@"    ""status"": ""ACTIVATION_REQUIRED""," + "\n" +
@"    ""policy"": {" + "\n" +
@"        ""id"": ""{{deviceAuthenticationPolicyID}}""" + "\n" +
@"    }" + "\n" +
@"}";
request.AddStringBody(body, DataFormat.Json);
RestResponse response = await client.ExecuteAsync(request);
Console.WriteLine(response.Content);
```

```golang
package main

import (
  "fmt"
  "strings"
  "net/http"
  "io"
)

func main() {

  url := "{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices"
  method := "POST"

  payload := strings.NewReader(`{
    "type": "PINGID_DESKTOP_GEN2",
    "status": "ACTIVATION_REQUIRED",
    "policy": {
        "id": "{{deviceAuthenticationPolicyID}}"
    }
}`)

  client := &http.Client {
  }
  req, err := http.NewRequest(method, url, payload)

  if err != nil {
    fmt.Println(err)
    return
  }
  req.Header.Add("Content-Type", "application/json")
  req.Header.Add("Authorization", "Bearer {{accessToken}}")

  res, err := client.Do(req)
  if err != nil {
    fmt.Println(err)
    return
  }
  defer res.Body.Close()

  body, err := io.ReadAll(res.Body)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(string(body))
}
```

```http
POST /environments/{{envID}}/users/{{userID}}/devices HTTP/1.1
Host: {{apiPath}}
Content-Type: application/json
Authorization: Bearer {{accessToken}}

{
    "type": "PINGID_DESKTOP_GEN2",
    "status": "ACTIVATION_REQUIRED",
    "policy": {
        "id": "{{deviceAuthenticationPolicyID}}"
    }
}
```

```java
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"type\": \"PINGID_DESKTOP_GEN2\",\n    \"status\": \"ACTIVATION_REQUIRED\",\n    \"policy\": {\n        \"id\": \"{{deviceAuthenticationPolicyID}}\"\n    }\n}");
Request request = new Request.Builder()
  .url("{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices")
  .method("POST", body)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer {{accessToken}}")
  .build();
Response response = client.newCall(request).execute();
```

```javascript
var settings = {
  "url": "{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices",
  "method": "POST",
  "timeout": 0,
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Bearer {{accessToken}}"
  },
  "data": JSON.stringify({
    "type": "PINGID_DESKTOP_GEN2",
    "status": "ACTIVATION_REQUIRED",
    "policy": {
      "id": "{{deviceAuthenticationPolicyID}}"
    }
  }),
};

$.ajax(settings).done(function (response) {
  console.log(response);
});
```

```javascript
var request = require('request');
var options = {
  'method': 'POST',
  'url': '{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices',
  'headers': {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {{accessToken}}'
  },
  body: JSON.stringify({
    "type": "PINGID_DESKTOP_GEN2",
    "status": "ACTIVATION_REQUIRED",
    "policy": {
      "id": "{{deviceAuthenticationPolicyID}}"
    }
  })

};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
```

```python
import requests
import json

url = "{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices"

payload = json.dumps({
  "type": "PINGID_DESKTOP_GEN2",
  "status": "ACTIVATION_REQUIRED",
  "policy": {
    "id": "{{deviceAuthenticationPolicyID}}"
  }
})
headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer {{accessToken}}'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)
```

```php
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices');
$request->setMethod(HTTP_Request2::METHOD_POST);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
$request->setHeader(array(
  'Content-Type' => 'application/json',
  'Authorization' => 'Bearer {{accessToken}}'
));
$request->setBody('{\n    "type": "PINGID_DESKTOP_GEN2",\n    "status": "ACTIVATION_REQUIRED",\n    "policy": {\n        "id": "{{deviceAuthenticationPolicyID}}"\n    }\n}');
try {
  $response = $request->send();
  if ($response->getStatus() == 200) {
    echo $response->getBody();
  }
  else {
    echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
    $response->getReasonPhrase();
  }
}
catch(HTTP_Request2_Exception $e) {
  echo 'Error: ' . $e->getMessage();
}
```

```ruby
require "uri"
require "json"
require "net/http"

url = URI("{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices")

http = Net::HTTP.new(url.host, url.port);
request = Net::HTTP::Post.new(url)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer {{accessToken}}"
request.body = JSON.dump({
  "type": "PINGID_DESKTOP_GEN2",
  "status": "ACTIVATION_REQUIRED",
  "policy": {
    "id": "{{deviceAuthenticationPolicyID}}"
  }
})

response = http.request(request)
puts response.read_body
```

```swift
let parameters = "{\n    \"type\": \"PINGID_DESKTOP_GEN2\",\n    \"status\": \"ACTIVATION_REQUIRED\",\n    \"policy\": {\n        \"id\": \"{{deviceAuthenticationPolicyID}}\"\n    }\n}"
let postData = parameters.data(using: .utf8)

var request = URLRequest(url: URL(string: "{{apiPath}}/environments/{{envID}}/users/{{userID}}/devices")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer {{accessToken}}", forHTTPHeaderField: "Authorization")

request.httpMethod = "POST"
request.httpBody = postData

let task = URLSession.shared.dataTask(with: request) { data, response, error in
  guard let data = data else {
    print(String(describing: error))
    return
  }
  print(String(data: data, encoding: .utf8)!)
}

task.resume()
```

### Example Response

201 Created

```json
{
    "_links": {
        "self": {
            "href": "https://api.pingone.eu/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/users/d4543f69-e508-4cc6-bd16-b61baa4b3caf/devices/0ac16146-5e05-d328-0ac1-61465e05d328"
        },
        "environment": {
            "href": "https://api.pingone.eu/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6"
        },
        "user": {
            "href": "https://api.pingone.eu/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/users/d4543f69-e508-4cc6-bd16-b61baa4b3caf"
        },
        "device.activate": {
            "href": "https://api.pingone.eu/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/users/d4543f69-e508-4cc6-bd16-b61baa4b3caf/devices/0ac16146-5e05-d328-0ac1-61465e05d328"
        }
    },
    "rp": {
        "id": "pingone.eu",
        "name": "pingone.eu"
    },
    "id": "0ac16146-5e05-d328-0ac1-61465e05d328",
    "environment": {
        "id": "abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6"
    },
    "user": {
        "id": "d4543f69-e508-4cc6-bd16-b61baa4b3caf"
    },
    "type": "PINGID_DESKTOP_GEN2",
    "status": "ACTIVATION_REQUIRED",
    "createdAt": "2026-02-16T11:51:34.153Z",
    "updatedAt": "2026-02-16T11:51:34.153Z",
    "os": {},
    "model": {},
    "pingIdDesktopCredentialCreationOptions": "{{desktopCredentialCreationOptionsValue}}"
}
```
