Register a single device
20 minute read
Device registration is the gate every IoT device passes through before it can request certificates, receive policy, or report state to DigiCert® Device Trust Manager. This tutorial explains how to use API calls to wire device onboarding into your provisioning pipeline.
In this tutorial, you will:
- Create a division to scope your devices and policies.
- Retrieve the division’s ID for use in later steps.
- Create a bootstrap certificate policy that defines how the device’s first certificate is issued.
- Create a device group and attach the bootstrap policy.
- Retrieve the device group’s ID for use in registration.
- Register the device against the device group.
Before you begin
Before you begin, make sure you have:
An API key with the following role:
DEVCTM_SOLUTION_ADMINISTRATORProvides division, policy, device group, and device creation.
ica_id for Step 3.certificate_profile_id for Step 3.primary_rzone_id for Step 1. You can retrieve it via the List all rendezvous zones endpoint.account_id. You can retrieve it via the DigiCert® Account Manager List accounts endpoint.Endpoint overview
| Method | Path | Description |
|---|---|---|
| POST | /devicetrustmanager/api/v4/division | Create a division |
| GET | /devicetrustmanager/api/v4/division | List divisions to retrieve the division ID |
| POST | /devicetrustmanager/certificate-configuration-service/api/v2/certificate-policy | Create a bootstrap certificate policy |
| POST | /devicetrustmanager/api/v4/device-group | Create a device group |
| GET | /devicetrustmanager/api/v4/device-group | List device groups to retrieve the device group ID |
| POST | /devicetrustmanager/api/v4/device/registration | Register a device |
Reference values
These enum-typed fields appear across the request bodies in Steps 3 and 4. Use this table as a quick lookup when constructing requests programmatically.
| Field | Used in | Allowed values |
|---|---|---|
certificate_management_methods | Step 3 | SINGLE, BATCH, TRUST_EDGE, EST, SCEP, CMP_V2, ACME |
key_generation_option | Step 3 | client_side, server_side, client_or_server_side |
policies[].type | Step 4 | bootstrapCertificate, operationalCertificate |
policies[].status | Step 4 | ACTIVE, DISABLED, DELETED, INVITE_SENT, READY, EXPIRED |
Step 1: Create a division
A division is an isolated container for your devices, policies, and device groups. Most production deployments organize divisions by business unit, product line, or customer tenant. Create one before any device-related resources so every resource you create afterward belongs to a known scope.
Request:
curl -X POST "https://demo.one.digicert.com/devicetrustmanager/api/v4/division" \
-H "x-api-key: API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Example division name",
"description": "Example division description.",
"account_id": "ACCOUNT_ID",
"primary_rzone_id": "PRIMARY_RZONE_ID"
}' | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
API_KEY = "API_KEY"
# Request details
NAME = "Example division name"
DESCRIPTION = "Example division description."
ACCOUNT_ID = "ACCOUNT_ID"
PRIMARY_RZONE_ID = "PRIMARY_RZONE_ID"
payload = {
"name": NAME,
"description": DESCRIPTION,
"account_id": ACCOUNT_ID,
"primary_rzone_id": PRIMARY_RZONE_ID,
}
response = requests.post(
f"{BASE_URL}/devicetrustmanager/api/v4/division",
headers={
"x-api-key": API_KEY,
"Content-Type": "application/json"
},
json=payload
)
print(f"Status Code: {response.status_code}")
print(response.json())import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ApiExample {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String adminApiKey = "ADMIN_API_KEY";
// Request details
String name = "Example division name";
String description = "Example division description.";
String accountId = "ACCOUNT_ID";
String primaryRzoneId = "PRIMARY_RZONE_ID";
// Build payload
ObjectMapper mapper = new ObjectMapper();
ObjectNode payload = mapper.createObjectNode();
payload.put("name", name);
payload.put("description", description);
payload.put("account_id", accountId);
payload.put("primary_rzone_id", primaryRzoneId);
// Send request
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/devicetrustmanager/api/v4/division"))
.header("x-api-key", adminApiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload)))
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println("Status Code: " + response.statusCode());
System.out.println(response.body());
}
}using System;
using System.Net.Http;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Configuration
string baseUrl = "https://demo.one.digicert.com";
string adminApiKey = "ADMIN_API_KEY";
// Request details
string name = "Example division name";
string description = "Example division description.";
string accountId = "ACCOUNT_ID";
string primaryRzoneId = "PRIMARY_RZONE_ID";
// Build payload
var payload = new JsonObject
{
["name"] = name,
["description"] = description,
["account_id"] = accountId,
["primary_rzone_id"] = primaryRzoneId
};
// Send request
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", adminApiKey);
var content = new StringContent(
payload.ToJsonString(),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync($"{baseUrl}/devicetrustmanager/api/v4/division", content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Set the body fields:
nameUnique division name (must start and end with an alphanumeric character).descriptionFree-form description shown in the UI and audit logs.account_idYour DigiCert ONE account ID (a valid UUID).primary_rzone_idThe rendezvous zone ID that will broker device communication for devices in this division.
Successful response (201 Created):
{
"success": {
"code": "DIVISION_CREATED_200",
"verbose": "Example division name created successfully"
}
}
This response carries only a success message — the new division’s id is not returned. Retrieve it via a list query in Step 2 before continuing.
Step 2: Get the division ID
The create-division endpoint returns only a success message, not the new division’s id. List divisions filtered by your account_id and the name you chose in Step 1 to retrieve its id, which you will pass as division_id to Steps 3 and 4.
Request:
curl -X GET "https://demo.one.digicert.com/devicetrustmanager/api/v4/division?account_id=ACCOUNT_ID&name=Example%20division%20name" \
-H "x-api-key: API_KEY" \
-H "Content-Type: application/json" | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
ADMIN_API_KEY = "ADMIN_API_KEY"
# Request details
ACCOUNT_ID = "ACCOUNT_ID"
DIVISION_NAME = "Example division name"
response = requests.get(
f"{BASE_URL}/devicetrustmanager/api/v4/division",
headers={
"x-api-key": API_KEY,
"Content-Type": "application/json"
},
params={
"account_id": ACCOUNT_ID,
"name": DIVISION_NAME
}
)
print(f"Status Code: {response.status_code}")
print(response.json())import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class ApiExample {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String adminApiKey = "ADMIN_API_KEY";
// Request details
String accountId = "ACCOUNT_ID";
String divisionName = "Example division name";
String query = "account_id=" + URLEncoder.encode(accountId, StandardCharsets.UTF_8)
+ "&name=" + URLEncoder.encode(divisionName, StandardCharsets.UTF_8);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/devicetrustmanager/api/v4/division?" + query))
.header("x-api-key", adminApiKey)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println("Status Code: " + response.statusCode());
System.out.println(response.body());
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Configuration
string baseUrl = "https://demo.one.digicert.com";
string adminApiKey = "ADMIN_API_KEY";
// Request details
string accountId = "ACCOUNT_ID";
string divisionName = "Example division name";
string query = $"account_id={Uri.EscapeDataString(accountId)}"
+ $"&name={Uri.EscapeDataString(divisionName)}";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", adminApiKey);
var response = await client.GetAsync($"{baseUrl}/devicetrustmanager/api/v4/division?{query}");
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Set the query parameters:
account_idYour DigiCert ONE account ID. Required to scope the search.nameDivision name from Step 1. The API returns divisions whose names contain this value. From the response, select the record whosenameexactly matches.
Successful response (200 OK):
{
"total": 1,
"limit": 10,
"offset": 0,
"pagination": false,
"next": false,
"records": [
{
"created_on": "2026-05-11T07:07:13Z",
"updated_on": "2026-05-11T07:07:13Z",
"name": "Example division name",
"description": "Example division description.",
"id": "<DIVISION_ID>",
"account": {
"id": "<ACCOUNT_ID>"
},
"status": "ACTIVE"
}
]
}
From the matching entry in the records array, save the id value as division_id. You will use it in Step 3 and Step 4 to scope the certificate policy and device group to this division.
Step 3: Create a bootstrap certificate policy
A bootstrap certificate policy defines how a device’s first certificate is requested and issued. A bootstrap certificate (also called a birth credential) is a long-lived X.509 certificate that establishes the device’s identity at provisioning and stays with the device throughout its lifecycle. Operational certificates, configured in a separate operational policy, are the short-lived credentials a device rotates for day-to-day work. Wiring policy creation into your provisioning pipeline means you can version policies as code and roll changes alongside firmware.
Request:
{
"certificate_policy": {
"name": "Example bootstrap policy",
"ica_id": "ICA_ID",
"division_id": "DIVISION_ID",
"certificate_profile_id": "CERT_PROFILE_ID",
"certificate_management_methods": [
"SINGLE"
],
"key_generation_option": "client_side"
}
}
curl -X POST "https://demo.one.digicert.com/devicetrustmanager/certificate-configuration-service/api/v2/certificate-policy" \
-H "x-api-key: API_KEY" \
-H "Content-Type: application/json" \
-d '{
"certificate_policy": {
"name": "Example bootstrap policy",
"ica_id": "ICA_ID",
"division_id": "DIVISION_ID",
"certificate_profile_id": "CERT_PROFILE_ID",
"certificate_management_methods": ["SINGLE"],
"key_generation_option": "client_side"
}
}' | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
ADMIN_API_KEY = "ADMIN_API_KEY"
# Request details
POLICY_NAME = "Example bootstrap policy"
ICA_ID = "ICA_ID"
DIVISION_ID = "DIVISION_ID"
CERT_PROFILE_ID = "CERT_PROFILE_ID"
payload = {
"certificate_policy": {
"name": POLICY_NAME,
"ica_id": ICA_ID,
"division_id": DIVISION_ID,
"certificate_profile_id": CERT_PROFILE_ID,
"certificate_management_methods": ["SINGLE"],
"key_generation_option": "client_side",
},
}
response = requests.post(
f"{BASE_URL}/devicetrustmanager/certificate-configuration-service/api/v2/certificate-policy",
headers={
"x-api-key": ADMIN_API_KEY,
"Content-Type": "application/json"
},
json=payload
)
print(f"Status Code: {response.status_code}")
print(response.json())import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ApiExample {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String adminApiKey = "ADMIN_API_KEY";
// Request details
String policyName = "Example bootstrap policy";
String icaId = "ICA_ID";
String divisionId = "DIVISION_ID";
String certProfileId = "CERT_PROFILE_ID";
// Build payload
ObjectMapper mapper = new ObjectMapper();
ObjectNode certificatePolicy = mapper.createObjectNode();
certificatePolicy.put("name", policyName);
certificatePolicy.put("ica_id", icaId);
certificatePolicy.put("division_id", divisionId);
certificatePolicy.put("certificate_profile_id", certProfileId);
ArrayNode methods = certificatePolicy.putArray("certificate_management_methods");
methods.add("SINGLE");
certificatePolicy.put("key_generation_option", "client_side");
ObjectNode payload = mapper.createObjectNode();
payload.set("certificate_policy", certificatePolicy);
// Send request
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/devicetrustmanager/certificate-configuration-service/api/v2/certificate-policy"))
.header("x-api-key", adminApiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload)))
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println("Status Code: " + response.statusCode());
System.out.println(response.body());
}
}using System;
using System.Net.Http;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Configuration
string baseUrl = "https://demo.one.digicert.com";
string adminApiKey = "ADMIN_API_KEY";
// Request details
string policyName = "Example bootstrap policy";
string icaId = "ICA_ID";
string divisionId = "DIVISION_ID";
string certProfileId = "CERT_PROFILE_ID";
// Build payload
var payload = new JsonObject
{
["certificate_policy"] = new JsonObject
{
["name"] = policyName,
["ica_id"] = icaId,
["division_id"] = divisionId,
["certificate_profile_id"] = certProfileId,
["certificate_management_methods"] = new JsonArray { "SINGLE" },
["key_generation_option"] = "client_side"
}
};
// Send request
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", adminApiKey);
var content = new StringContent(
payload.ToJsonString(),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync($"{baseUrl}/devicetrustmanager/certificate-configuration-service/api/v2/certificate-policy", content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}certificate_policy object. The inner certificate_policy object holds the fields described below. Sending the fields at the top level returns a 400.Set these inner certificate_policy fields:
| Field | Guidance |
|---|---|
name | Friendly certificate policy name. |
ica_id | ID of the issuing CA from DigiCert Private CA that will sign certificates for this policy. |
division_id | The division_id from Step 2. |
certificate_profile_id | Certificate profile ID from DigiCert Private CA that shapes the issued certificate. |
certificate_management_methods | Use ["SINGLE"] for one-at-a-time issuance during device registration. |
key_generation_option | Use client_side so the device supplies a CSR and keeps the private key. |
See Reference values for allowed values for certificate_management_methods and key_generation_option.
Successful response (201 Created):
{
"certificate_policy": {
"name": "Example bootstrap policy",
"certificate_management_methods": [
"SINGLE"
],
"enrollment_methods": [
"SINGLE"
],
"allowed_ip_addresses": [],
"key_generation_type": "rsa_2048",
"key_generation_allow_to_change": false,
"key_generation_option": "client_side",
"allow_pre_generated_keys": false,
"ca_connector_type": "digicert_one",
"assign_to_authcert_device": false,
"allow_key_cache": false,
"division_id": "<DIVISION_ID>",
"require_approval_for_enroll": false,
"require_approval_for_renew": false,
"notification_email_list": [],
"digest_email_notification_period": "do_not_send",
"require_digital_signing": false,
"new_batch_flow": true,
"single_cert_request_parameters": {
"key_generation_option": "client_side",
"key_generation_allow_to_change": false,
"allow_to_use_pregenerated_keys": false,
"private_key_format": "pem",
"allow_key_cache": false,
"rsa_private_key_syntax": "pkcs8",
"ecdsa_private_key_syntax": "pkcs8",
"response_with_certificate_only": false,
"split_certificate_response": true,
"include_chain_option": "include_ica_and_root"
},
"require_device_group_for_enroll": false,
"migrated_to_new_params": false,
"scep_get_ca_cert_response_with_root": false,
"scep_get_ca_cert_response_der_format": false,
"est_cacerts_include_full_tls_chain": false,
"id": "<CERTIFICATE_POLICY_ID>",
"certificate_profile": {
"id": "<CERT_PROFILE_ID>",
"name": "Example certificate profile"
},
"created_at": "2026-05-04T19:14:55Z",
"ica": {
"id": "<ICA_ID>",
"name": "Example Intermediate CA"
},
"status": "ACTIVE",
"allowed_signature_algorithms": [
"MLDSA-65"
],
"direct_mapping": true,
"account_id": "<ACCOUNT_ID>",
"certificate_type": "end_entity",
"approvers": [],
"ca_body": "<CA_BODY>",
"ca_chain": [
{
"cert_type": "intermediate",
"blob": "<ICA_BLOB>",
"common_name": "Example intermediate CA"
},
{
"cert_type": "root",
"blob": "<ROOT_CA_BLOB>",
"common_name": "Example root CA"
}
],
"certificate_template": {
"id": "<CERT_TEMPLATE_ID>",
"name": "Example certificate template"
},
"require_approval_for_revoke": false,
"alternative_id": "<ALT_ID>"
}
}
From the response, save the certificate policy’s id value as certificate_policy_id. You will use it in Step 4 when you attach the policy to the device group, and in Step 6 when you register the device against the policy.
Step 4: Create a device group with the bootstrap policy attached
A device group is a logical bucket of devices that share the same policies and assignment rules. Attaching the bootstrap certificate policy to the device group at creation time means every device registered to the group will use that policy automatically. That way registration becomes a single API call rather than a per-device policy assignment.
Request:
{
"name": "Example Device Group",
"description": "Custom description",
"is_static": true,
"account_id": "ACCOUNT_ID",
"division_id": "DIVISION_ID",
"attributes": [
"mac_address"
],
"policies": [
{
"type": "bootstrapCertificate",
"policy_id": "CERTIFICATE_POLICY_ID",
"assignment_name": "Bootstrap policy assignment",
"device_field_mappings": [
{
"key": "mac_address",
"field": "subject.common_name"
}
],
"status": "ACTIVE"
}
]
}
curl -X POST "https://demo.one.digicert.com/devicetrustmanager/api/v4/device-group" \
-H "x-api-key: API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Example Device Group",
"description": "Custom description",
"is_static": true,
"account_id": "ACCOUNT_ID",
"division_id": "DIVISION_ID",
"attributes": ["mac_address"],
"policies": [
{
"type": "bootstrapCertificate",
"policy_id": "CERTIFICATE_POLICY_ID",
"assignment_name": "Bootstrap policy assignment",
"device_field_mappings": [
{ "key": "mac_address", "field": "subject.common_name" }
],
"status": "ACTIVE"
}
]
}' | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
ADMIN_API_KEY = "ADMIN_API_KEY"
# Request details
NAME = "Example Device Group"
DESCRIPTION = "Custom description"
ACCOUNT_ID = "ACCOUNT_ID"
DIVISION_ID = "DIVISION_ID"
CERTIFICATE_POLICY_ID = "CERTIFICATE_POLICY_ID"
payload = {
"name": NAME,
"description": DESCRIPTION,
"is_static": True,
"account_id": ACCOUNT_ID,
"division_id": DIVISION_ID,
"attributes": ["mac_address"],
"policies": [
{
"type": "bootstrapCertificate",
"policy_id": CERTIFICATE_POLICY_ID,
"assignment_name": "Bootstrap policy assignment",
"device_field_mappings": [
{"key": "mac_address", "field": "subject.common_name"}
],
"status": "ACTIVE",
}
],
}
response = requests.post(
f"{BASE_URL}/devicetrustmanager/api/v4/device-group",
headers={
"x-api-key": ADMIN_API_KEY,
"Content-Type": "application/json"
},
json=payload
)
print(f"Status Code: {response.status_code}")
print(response.json())import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ApiExample {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String adminApiKey = "ADMIN_API_KEY";
// Request details
String name = "Example Device Group";
String description = "Custom description";
String accountId = "ACCOUNT_ID";
String divisionId = "DIVISION_ID";
String certificatePolicyId = "CERTIFICATE_POLICY_ID";
// Build payload
ObjectMapper mapper = new ObjectMapper();
ObjectNode payload = mapper.createObjectNode();
payload.put("name", name);
payload.put("description", description);
payload.put("is_static", true);
payload.put("account_id", accountId);
payload.put("division_id", divisionId);
ArrayNode attributesArray = payload.putArray("attributes");
attributesArray.add("mac_address");
ObjectNode fieldMapping = mapper.createObjectNode();
fieldMapping.put("key", "mac_address");
fieldMapping.put("field", "subject.common_name");
ObjectNode policy = mapper.createObjectNode();
policy.put("type", "bootstrapCertificate");
policy.put("policy_id", certificatePolicyId);
policy.put("assignment_name", "Bootstrap policy assignment");
policy.putArray("device_field_mappings").add(fieldMapping);
policy.put("status", "ACTIVE");
payload.putArray("policies").add(policy);
// Send request
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/devicetrustmanager/api/v4/device-group"))
.header("x-api-key", adminApiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload)))
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println("Status Code: " + response.statusCode());
System.out.println(response.body());
}
}using System;
using System.Net.Http;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Configuration
string baseUrl = "https://demo.one.digicert.com";
string adminApiKey = "ADMIN_API_KEY";
// Request details
string name = "Example Device Group";
string description = "Custom description";
string accountId = "ACCOUNT_ID";
string divisionId = "DIVISION_ID";
string certificatePolicyId = "CERTIFICATE_POLICY_ID";
// Build payload
var payload = new JsonObject
{
["name"] = name,
["description"] = description,
["is_static"] = true,
["account_id"] = accountId,
["division_id"] = divisionId,
["attributes"] = new JsonArray { "mac_address" },
["policies"] = new JsonArray
{
new JsonObject
{
["type"] = "bootstrapCertificate",
["policy_id"] = certificatePolicyId,
["assignment_name"] = "Bootstrap policy assignment",
["device_field_mappings"] = new JsonArray
{
new JsonObject
{
["key"] = "mac_address",
["field"] = "subject.common_name"
}
},
["status"] = "ACTIVE"
}
}
};
// Send request
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", adminApiKey);
var content = new StringContent(
payload.ToJsonString(),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync($"{baseUrl}/devicetrustmanager/api/v4/device-group", content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Set the body fields:
nameDevice group name (must start and end with an alphanumeric character).descriptionFree-form description.is_staticUsetruefor a manually managed group. Set tofalsefor a dynamic group whose membership is driven by attribute-matching rules.account_idAccount ID for device association.division_idThedivision_idfrom Step 2.attributesInventory attribute values that uniquely identify devices in this group. For example,["mac_address"].policiesAn array describing policies attached to the group. For a bootstrap-only group, include one entry shaped like the example below:{ "type": "bootstrapCertificate", "policy_id": "<certificate_policy_id from Step 3>", "assignment_name": "Bootstrap policy assignment", "device_field_mappings": [ { "key": "mac_address", "field": "subject.common_name" } ], "status": "ACTIVE" }typemust bebootstrapCertificate(oroperationalCertificatefor an operational policy).device_field_mappingsties an inventory attribute (key) to a certificate subject field (field).Confirm subject field naming convention by queryingGET /devicetrustmanager/certificate-configuration-service/api/v2/certificate-policy/{PolicyID}/enrollment-specificationfor the chosen policy. The exact validfieldvalues are policy-dependent.
Successful response (201 Created):
{
"success": {
"code": "DEVICE_GROUP_CREATED_200",
"verbose": "Device group created"
}
}
Like the create-division endpoint in Step 1, this response carries only a success message — the new device group’s id is not returned. Retrieve it via a list query in Step 5 before registering the device.
Step 5: Get the device group ID
The create-device-group endpoint returns only a success message, not the new device group’s id. List device groups filtered by your account_id and the name you chose in Step 4 to retrieve its id, which you will pass as device_group_id to Step 6.
Request:
curl -X GET "https://demo.one.digicert.com/devicetrustmanager/api/v4/device-group?account_id=ACCOUNT_ID&name=Example%20Device%20Group" \
-H "x-api-key: API_KEY" \
-H "Content-Type: application/json" | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
ADMIN_API_KEY = "ADMIN_API_KEY"
# Request details
ACCOUNT_ID = "ACCOUNT_ID"
DEVICE_GROUP_NAME = "Example Device Group"
response = requests.get(
f"{BASE_URL}/devicetrustmanager/api/v4/device-group",
headers={
"x-api-key": ADMIN_API_KEY,
"Content-Type": "application/json"
},
params={
"account_id": ACCOUNT_ID,
"name": DEVICE_GROUP_NAME
}
)
print(f"Status Code: {response.status_code}")
print(response.json())import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class ApiExample {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String adminApiKey = "ADMIN_API_KEY";
// Request details
String accountId = "ACCOUNT_ID";
String deviceGroupName = "Example Device Group";
String query = "account_id=" + URLEncoder.encode(accountId, StandardCharsets.UTF_8)
+ "&name=" + URLEncoder.encode(deviceGroupName, StandardCharsets.UTF_8);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/devicetrustmanager/api/v4/device-group?" + query))
.header("x-api-key", adminApiKey)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println("Status Code: " + response.statusCode());
System.out.println(response.body());
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Configuration
string baseUrl = "https://demo.one.digicert.com";
string adminApiKey = "ADMIN_API_KEY";
// Request details
string accountId = "ACCOUNT_ID";
string deviceGroupName = "Example Device Group";
string query = $"account_id={Uri.EscapeDataString(accountId)}"
+ $"&name={Uri.EscapeDataString(deviceGroupName)}";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", adminApiKey);
var response = await client.GetAsync($"{baseUrl}/devicetrustmanager/api/v4/device-group?{query}");
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Set the query parameters:
account_idYour DigiCert ONE account ID. Required to scope the search.nameDevice group name from Step 4. The API returns device groups whose names contain this value. From the response, select the record whosenameexactly matches.
Successful response (200 OK):
{
"total": 1,
"limit": 10,
"offset": 0,
"pagination": false,
"next": false,
"records": [
{
"created_on": "2026-05-11T07:14:55Z",
"updated_on": "2026-05-11T07:14:55Z",
"name": "Example Device Group",
"description": "Custom description",
"id": "<DEVICE_GROUP_ID>",
"account_id": "<ACCOUNT_ID>",
"division_id": "<DIVISION_ID>",
"is_static": true,
"status": "ACTIVE"
}
]
}
From the matching entry in the records array, save the id value as device_group_id. You will use it in Step 6 to register the device against this group.
Step 6: Register the device
With the division, certificate policy, and device group in place, you can register the device. Registration creates the device record, ties it to the group’s bootstrap policy, and triggers issuance of the device’s first certificate using the CSR you provide.
Request:
{
"name": "Example Device",
"description": "Example Device description",
"device_group_id": "DEVICE_GROUP_ID",
"account_id": "ACCOUNT_ID",
"certificate_policies": {
"bootstrap": [
{
"csr": "BOOTSTRAP_CSR",
"certificate_policy_id": "BOOTSTRAP_POLICY_ID",
"attributes": [
{
"name": "subject.common_name",
"value": "device-001"
}
]
}
]
}
}
curl -X POST "https://demo.one.digicert.com/devicetrustmanager/api/v4/device/registration" \
-H "x-api-key: API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Example Device",
"description": "Example Device description",
"device_group_id": "DEVICE_GROUP_ID",
"account_id": "ACCOUNT_ID",
"certificate_policies": {
"bootstrap": [
{
"csr": "BOOTSTRAP_CSR",
"certificate_policy_id": "BOOTSTRAP_POLICY_ID",
"attributes": [
{ "name": "subject.common_name", "value": "device-001" }
]
}
]
}
}' | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
ADMIN_API_KEY = "ADMIN_API_KEY"
# Request details
DEVICE_NAME = "Example Device"
DEVICE_DESCRIPTION = "Example Device description"
DEVICE_GROUP_ID = "DEVICE_GROUP_ID"
ACCOUNT_ID = "ACCOUNT_ID"
BOOTSTRAP_POLICY_ID = "BOOTSTRAP_POLICY_ID"
BOOTSTRAP_CSR = "BOOTSTRAP_CSR"
payload = {
"name": DEVICE_NAME,
"description": DEVICE_DESCRIPTION,
"device_group_id": DEVICE_GROUP_ID,
"account_id": ACCOUNT_ID,
"certificate_policies": {
"bootstrap": [
{
"csr": BOOTSTRAP_CSR,
"certificate_policy_id": BOOTSTRAP_POLICY_ID,
"attributes": [
{"name": "subject.common_name", "value": "device-001"}
],
}
],
},
}
response = requests.post(
f"{BASE_URL}/devicetrustmanager/api/v4/device/registration",
headers={
"x-api-key": ADMIN_API_KEY,
"Content-Type": "application/json"
},
json=payload
)
print(f"Status Code: {response.status_code}")
print(response.json())import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ApiExample {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String adminApiKey = "ADMIN_API_KEY";
// Request details
String deviceName = "Example Device";
String deviceDescription = "Example Device description";
String deviceGroupId = "DEVICE_GROUP_ID";
String accountId = "ACCOUNT_ID";
String bootstrapPolicyId = "BOOTSTRAP_POLICY_ID";
String bootstrapCsr = "BOOTSTRAP_CSR";
// Build payload
ObjectMapper mapper = new ObjectMapper();
ObjectNode payload = mapper.createObjectNode();
payload.put("name", deviceName);
payload.put("description", deviceDescription);
payload.put("device_group_id", deviceGroupId);
payload.put("account_id", accountId);
ObjectNode bootstrapAttribute = mapper.createObjectNode();
bootstrapAttribute.put("name", "subject.common_name");
bootstrapAttribute.put("value", "device-001");
ObjectNode bootstrapEntry = mapper.createObjectNode();
bootstrapEntry.put("csr", bootstrapCsr);
bootstrapEntry.put("certificate_policy_id", bootstrapPolicyId);
bootstrapEntry.putArray("attributes").add(bootstrapAttribute);
ObjectNode certificatePolicies = mapper.createObjectNode();
certificatePolicies.putArray("bootstrap").add(bootstrapEntry);
payload.set("certificate_policies", certificatePolicies);
// Send request
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/devicetrustmanager/api/v4/device/registration"))
.header("x-api-key", adminApiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload)))
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println("Status Code: " + response.statusCode());
System.out.println(response.body());
}
}using System;
using System.Net.Http;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Configuration
string baseUrl = "https://demo.one.digicert.com";
string adminApiKey = "ADMIN_API_KEY";
// Request details
string deviceName = "Example Device";
string deviceDescription = "Example Device description";
string deviceGroupId = "DEVICE_GROUP_ID";
string accountId = "ACCOUNT_ID";
string bootstrapPolicyId = "BOOTSTRAP_POLICY_ID";
string bootstrapCsr = "BOOTSTRAP_CSR";
// Build payload
var payload = new JsonObject
{
["name"] = deviceName,
["description"] = deviceDescription,
["device_group_id"] = deviceGroupId,
["account_id"] = accountId,
["certificate_policies"] = new JsonObject
{
["bootstrap"] = new JsonArray
{
new JsonObject
{
["csr"] = bootstrapCsr,
["certificate_policy_id"] = bootstrapPolicyId,
["attributes"] = new JsonArray
{
new JsonObject
{
["name"] = "subject.common_name",
["value"] = "device-001"
}
}
}
}
}
};
// Send request
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", adminApiKey);
var content = new StringContent(
payload.ToJsonString(),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync($"{baseUrl}/devicetrustmanager/api/v4/device/registration", content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Set the body fields:
nameThe device name (must be unique within the device group).descriptionFree-form description.device_group_idThedevice_group_idfrom Step 5.account_idYour DigiCert ONE account ID.certificate_policiesAn object containing abootstraparray. Each array entry is shaped like the example below:{ "certificate_policy_id": "<certificate_policy_id from Step 3>", "attributes": [ { "name": "subject.common_name", "value": "device-001" } ], "csr": "<PEM-encoded CSR>" }Each
attributesentry maps a subject field name (name) to a value (value). The endpoint also accepts anoperationalarray with the same shape for issuing the device’s first operational certificate at registration. Creating an operational policy and using that array is covered in What’s next?.
Successful response (201 Created):
{
"device_id": "<DEVICE_ID>",
"device_name": "Example Device",
"created_on": 1777923541028,
"connected": false,
"description": "Example Device description",
"device_status": "REGISTERED",
"operational_status": "ENABLED",
"private_keys": [
{
"policy_id": "<CERT_POLICY_ID>",
"policy_type": "BOOTSTRAP",
"certificate": "<DEVICE_CERTIFICATE>"
}
]
}
From the response, save the device’s device_id value. The private_keys[].certificate field carries the issued bootstrap certificate, which the device must install to complete onboarding.
Common errors and solutions
For general API errors (authentication, rate limits), see Error handling and rate limits.
Invalid name
{
"errors": [
{
"code": "03",
"message": "Name must start with a letter and end with an alphanumeric character. Accepts spaces, special chars (,.;:_-) and simple balanced parentheses."
}
]
}
The name field on division, certificate policy, device group, and device must start with a letter and end with an alphanumeric character. Trailing or leading special characters (-, ., ;, :, _, ,) cause this error. Strip whitespace and review the name format before retrying.
Invalid UUID
{
"errors": [
{
"code": "03",
"message": "Account id should be a valid UUID."
}
]
}
The account_id, division_id, certificate_policy_id, ica_id, certificate_profile_id, and device_group_id fields must be valid UUIDs. This error commonly appears when copying values from a UI that wraps IDs in display formatting. Confirm each ID is a bare UUID with no surrounding quotes, brackets, or whitespace.
Missing required field
{
"errors": [
{
"code": "missing_required_field",
"message": "Name cannot be empty or null or just spaces."
}
]
}
The POST endpoints in this tutorial reject empty or whitespace-only required fields. Audit the request body against the required-field list at the top of each step before retrying.
What’s next?
Now that the device is registered with a bootstrap certificate, you can:
- Register devices in batch: Use the batch device registration endpoint to onboard many devices at once from a CSV.
- Issue an operational certificate: Create an operational certificate policy and attach it to the device group. Devices authenticate with their long-lived bootstrap credential to request short-lived operational certificates for day-to-day work.
- Add an authentication policy: Configure mutual TLS or passcode-based authentication on the device registration endpoint so devices can re-authenticate without an admin API key.
- Monitor device activity: Wire device events into your monitoring stack. Events such as failed enrollments, certificate issuance, and policy changes are surfaced in Device Trust Manager audit logs.