PingOne Platform APIs

Step 8: Set user device (SMS)

   

POST {{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/devices

The POST {{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/devices operation creates an MFA device and associates this device with the specified user. The user must have an associated device to complete an MFA authentication action. The user can then receive a one-time passcode by text message.

In this request:

  • {{apiPath}} is the geographic domain for the PingOne API endpoints for your PingOne environment. The PingOne top-level domain is https://api.pingone.com/v1 for the U.S. Refer to PingOne API domains for the top-level domains for other regions.

  • {{envID}} is the ID of the environment you created in the previous step. If you’re using Postman, this value is automatically set by the script in the Script tab used for the previous step.

  • {{sharedUserID}} is the ID for the user you created in the step to create a user. If you’re using Postman, this has been automatically set for you by the script in the Script tab when you created the new user.

In the request body:

  • type is the type of device communication to use. In this case, the value must be "SMS".

  • phone is the user’s phone number for the phone that’ll be used for MFA. The phone number must be specified in international format (includes a leading + character), such as "+14155552671". The following are examples of valid phone values for the same phone number:

    +1.5125201234
    +15125201234
    +1.512.520.1234
    +1 (512) 520-1234

A successful response returns a Status: 200 successful message, and shows the user’s password status of OK.

You’re now ready to create an SSO workflow for this test environment using the PingOne APIs. Refer to Create an SSO Workflow.

Troubleshooting

  • Verify that {{envID}} is the ID for the new test environment you created.

  • Verify that you’ve assigned either the Environment Admin or Identity Admin role to your Worker app. Refer to Assign roles to the Worker app.

  • Verify that the {{sharedUserID}} value is the user ID value returned by the step to create a user. For Postman users, unassigned variables are shown in red, and assigned variables in blue.

  • Verify that you’re using Bearer authorization for this request (and all {{apiPath}} requests). For Postman users, check that the Authorization tab in Postman is set to Bearer Token, and the access token variable is assigned (shown in blue, not red).

  • If you get a 401 Unauthorized message, this is likely due to the access token expiring (a 1 hour expiry time). Refer to the step to get an access token, and call this request again.

  • Verify that {{apiPath}} is correct for your geographic domain .

Headers

Authorization      Bearer {{accessToken}}

Content-Type      application/json

Body

raw ( application/json )

{
    "type": "SMS",
    "phone": "{{phone}}"
}

Example Request

  • cURL

  • C#

  • Go

  • HTTP

  • Java

  • jQuery

  • NodeJS

  • Python

  • PHP

  • Ruby

  • Swift

curl --location --globoff '{{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/devices' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{accessToken}}' \
--data '{
    "type": "SMS",
    "phone": "{{phone}}"
}'
var options = new RestClientOptions("{{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/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"": ""SMS""," + "\n" +
@"    ""phone"": ""{{phone}}""" + "\n" +
@"}";
request.AddStringBody(body, DataFormat.Json);
RestResponse response = await client.ExecuteAsync(request);
Console.WriteLine(response.Content);
package main

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

func main() {

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

  payload := strings.NewReader(`{
    "type": "SMS",
    "phone": "{{phone}}"
}`)

  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))
}
POST /environments/{{envID}}/users/{{sharedUserID}}/devices HTTP/1.1
Host: {{apiPath}}
Content-Type: application/json
Authorization: Bearer {{accessToken}}

{
    "type": "SMS",
    "phone": "{{phone}}"
}
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"type\": \"SMS\",\n    \"phone\": \"{{phone}}\"\n}");
Request request = new Request.Builder()
  .url("{{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/devices")
  .method("POST", body)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer {{accessToken}}")
  .build();
Response response = client.newCall(request).execute();
var settings = {
  "url": "{{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/devices",
  "method": "POST",
  "timeout": 0,
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Bearer {{accessToken}}"
  },
  "data": JSON.stringify({
    "type": "SMS",
    "phone": "{{phone}}"
  }),
};

$.ajax(settings).done(function (response) {
  console.log(response);
});
var request = require('request');
var options = {
  'method': 'POST',
  'url': '{{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/devices',
  'headers': {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {{accessToken}}'
  },
  body: JSON.stringify({
    "type": "SMS",
    "phone": "{{phone}}"
  })

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

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

payload = json.dumps({
  "type": "SMS",
  "phone": "{{phone}}"
})
headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer {{accessToken}}'
}

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

print(response.text)
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('{{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/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": "SMS",\n    "phone": "{{phone}}"\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();
}
require "uri"
require "json"
require "net/http"

url = URI("{{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/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": "SMS",
  "phone": "{{phone}}"
})

response = http.request(request)
puts response.read_body
let parameters = "{\n    \"type\": \"SMS\",\n    \"phone\": \"{{phone}}\"\n}"
let postData = parameters.data(using: .utf8)

var request = URLRequest(url: URL(string: "{{apiPath}}/environments/{{envID}}/users/{{sharedUserID}}/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

{
    "_links": {
        "self": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/users/b7119e13-9612-42d0-a57c-039e74a0f27c/devices/eb8707c3-2d59-48d4-b59c-1e3b60b27d74"
        },
        "environment": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6"
        },
        "user": {
            "href": "https://api.pingone.com/v1/environments/abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6/users/b7119e13-9612-42d0-a57c-039e74a0f27c"
        }
    },
    "id": "eb8707c3-2d59-48d4-b59c-1e3b60b27d74",
    "environment": {
        "id": "abfba8f6-49eb-49f5-a5d9-80ad5c98f9f6"
    },
    "user": {
        "id": "b7119e13-9612-42d0-a57c-039e74a0f27c"
    },
    "type": "SMS",
    "status": "ACTIVE",
    "createdAt": "2026-03-23T16:43:37.211Z",
    "updatedAt": "2026-03-23T16:43:37.211Z",
    "phone": "1-234-567-8900"
}