Create and authenticate a service user
11 minute read
Service users are designed for automation. They persist regardless of employee turnover and enable granular permission control for API integrations.
In this tutorial, you will:
- Get the account ID to assign the service user.
- Identify available roles and permissions for the service user.
- Create the service user.
- Use the returned API token to authenticate your first API call as that service user.
Before you begin
curl, jq installed. Use jq --version to verify.Endpoint overview
| Path | Method | Description |
|---|---|---|
/account/api/v1/account | GET | Retrieve a list of accounts you have access to |
/account/api/v1/role | GET | Retrieve a list of roles and associated permissions available to assign |
/account/api/v1/user | POST | Create a new service user with specified roles and permissions |
/account/api/v1/user/me | GET | Get details about the currently authenticated user |
Step 1: Get your account ID
Service users must be assigned to at least one account. You can find the account ID to assign using the /account/api/v1/account endpoint.
Request:
curl -X GET https://demo.one.digicert.com/account/api/v1/account \
-H "x-api-key: ADMIN_API_KEY" \
-H "Content-Type: application/json" | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
API_KEY = "ADMIN_API_KEY"
# Get accounts
response = requests.get(
f"{BASE_URL}/account/api/v1/account",
headers={
"x-api-key": API_KEY,
"Content-Type": "application/json"
}
)
# Check response
if response.status_code == 200:
accounts = response.json()
print("Accounts retrieved successfully:")
for account in accounts:
print(f" - {account['name']} (ID: {account['id']})")
else:
print(f"Error {response.status_code}: {response.text}")import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import org.json.JSONArray;
import org.json.JSONObject;
public class AccountExample {
private static final String BASE_URL = "https://demo.one.digicert.com";
private static final String API_KEY = "YOUR_API_KEY";
public static void main(String[] args) {
try {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/account/api/v1/account"))
.header("x-api-key", API_KEY)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() == 200) {
JSONArray accounts = new JSONArray(response.body());
System.out.println("Accounts retrieved successfully:");
for (int i = 0; i < accounts.length(); i++) {
JSONObject account = accounts.getJSONObject(i);
System.out.println(" - " + account.getString("name") +
" (ID: " + account.getString("id") + ")");
}
} else {
System.err.println("Error " + response.statusCode() + ": " +
response.body());
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}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";
// Get accounts
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", adminApiKey);
client.DefaultRequestHeaders.Add("Content-Type", "application/json");
var response = await client.GetAsync(
$"{baseUrl}/account/api/v1/account"
);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Successful response (200 OK):
[
{
"id": "50580ac7-60e4-4df2-a834-d12c1ab79afb",
"name": "Example account 1",
"active": true,
"service_period": {
"from": "2021-05-25",
"to": "2022-05-25"
},
"friendly_identifier": "5258283",
"admins": [
{
"id": "833e4906-fc45-4bd3-841e-40506c0e8ca8",
"email": "api_service_user_1@example.com"
},
{
"id": "fa8285c7-5e35-4ea8-8cc4-dc95f7dc3cd6",
"email": "api_service_user_2@example.com"
},
{
"id": "7d78b46a-c635-4bda-8b6d-13802046a963",
"name": "John Doe",
"email": "account_user_1@example.com"
}
],
"sign_in_methods": [
{
"signInMethod": "standard",
"status": "enabled",
"mfaStatus": "disabled",
"clientAuthCertLoginEnabled": false
}
],
"locale": "en_US"
},
{
"id": "be5ffbd2-1a50-4675-912f-2fe015812f87",
"name": "Example account 2",
"active": true,
"service_period": {
"from": "2021-05-26",
"to": "2022-05-26"
},
"friendly_identifier": "7092363",
"admins": [],
"sign_in_methods": [
{
"signInMethod": "standard",
"status": "enabled",
"mfaStatus": "disabled",
"clientAuthCertLoginEnabled": false
}
],
"locale": "en_US"
}
]
From the returned list of accounts, choose the account you want to work with and save its id value. You will need this in Step 3 when you create the service user.
Step 2: View available roles and permissions
Before creating a service user, you need to understand which roles are available in your account. Roles determine what a user (service user in this case) can see and do via the API.
The /account/api/v1/role endpoint returns all roles (default and custom) and are organized by manager.
Request:
curl -X GET https://demo.one.digicert.com/account/api/v1/role \
-H "x-api-key: SERVICE_API_TOKEN" \
-H "Content-Type: application/json" | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
SERVICE_API_TOKEN = "SERVICE_API_TOKEN"
# Get user roles
response = requests.get(
f"{BASE_URL}/account/api/v1/role",
headers={
"x-api-key": SERVICE_API_TOKEN,
"Content-Type": "application/json"
}
)
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;
public class Example {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String serviceApiToken = "SERVICE_API_TOKEN";
// Get user roles
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/account/api/v1/role"))
.header("x-api-key", serviceApiToken)
.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 serviceApiToken = "SERVICE_API_TOKEN";
// Get user roles
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", serviceApiToken);
client.DefaultRequestHeaders.Add("Content-Type", "application/json");
var response = await client.GetAsync(
$"{baseUrl}/account/api/v1/role"
);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Successful response (200 OK):
{
"ca_manager": [
{
"name": "CM_PKI_MANAGER",
"display_name": "CM PKI MANAGER",
"description": "Role with CM view permissions",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "CM_KEY_ESCROW",
"display_name": "Key Escrow",
"description": "CM Key Escrow",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
}
],
"account_manager": [
{
"name": "AM_ACCOUNT_ADMIN",
"display_name": "AM ACCOUNT ADMIN",
"description": "Admin role with view and manage permissions",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "AM_DEFAULT_USER",
"display_name": "AM DEFAULT USER",
"description": "Default role with view permissions",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "AM_ACCOUNT_USER",
"display_name": "AM ACCOUNT USER",
"description": "Role with view permissions",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "AM_ACCOUNT_MANAGER",
"display_name": "Account manager",
"description": "AM Account manager",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "AM_USER_MANAGER",
"display_name": "User manager",
"description": "AM User manager",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "AM_VIEW_ONLY",
"display_name": "View only",
"description": "AM View only",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
}
],
"secure_software_manager": [
{
"name": "SSM_KEYLOCKER_ADMIN",
"display_name": "SSM KEYLOCKER ADMIN",
"description": "Admin role with view and manage SSM permissions",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "SSM_KEYLOCKER_USER",
"display_name": "SSM KEYLOCKER USER",
"description": "Admin lite role",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "SSM_LEAD",
"display_name": "SSM Lead",
"description": "SSM Lead",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "SSM_DEVELOPER",
"display_name": "SSM Developer",
"description": "SSM Developer",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "SSM_TEAM_LEAD",
"display_name": "SSM Team Lead",
"description": "SSM Team Lead",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "SSM_SIGNER",
"display_name": "SSM Signer",
"description": "SSM Signer",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
}
],
"enterprise_manager": [
{
"name": "EM_EPKI_ACCOUNT_MANAGER",
"display_name": "EPKI Account Manager",
"description": "EPKI Account Manager",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "EM_EPKI_RECOVERY_MANAGER",
"display_name": "EPKI Recovery Manager",
"description": "EPKI Recovery Manager",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "EM_EPKI_IMPORT_MANAGER",
"display_name": "EPKI Import Manager",
"description": "EPKI Import Manager",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "EM_EPKI_USER_&_CERT_MANAGER",
"display_name": "EPKI User & cert manager",
"description": "EPKI User & cert manager",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "EM_EPKI_CERT_PROFILE_MANAGER",
"display_name": "EPKI Cert Profile Manager",
"description": "EPKI Cert Profile Manager",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
}
],
"device_manager": [
{
"name": "IOT_CUSTOM_ROLE",
"display_name": "Custom role",
"description": "Custom role description.",
"type": "custom",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "IOT_ACCOUNT_MANAGER",
"display_name": "IOT Account Manager",
"description": "IOT Account Manager",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
}
],
"document_signing_manager": [
{
"name": "DSM_DOCUMENT_SIGNER",
"display_name": "DSM DOCUMENT SIGNER",
"description": "Role with signer permissions",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "DSM_CLIENT_ADMIN",
"display_name": "DSM Client Admin",
"description": "DSM Client Admin",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
},
{
"name": "DSM_SIGNER",
"display_name": "DSM Signer",
"description": "DSM Signer",
"type": "default",
"status": "ACTIVE",
"access_scope": "account"
}
]
}
The response body returns a list of user roles for your account. By default, it returns all roles (both default system roles and custom roles) for your primary account, organized by manager.
account_manager: Account managerca_manager: DigiCert® Private CAenterprise_manager: Trust Lifecycledevice_trust_manager: Device Trustsecure_software_manager: Software Trustdocument_signing_manager: Document Trustdevice_manager: IoT Trust
Each role object in the response contains these fields:
name: The role identifier used in API requests.display_name: Friendly role namedescription: What the role allows users to dotype: Whether it’s adefaultsystem role orcustomrolestatus: Whether the role isACTIVEorARCHIVED
When you create a service user in the next step, you’ll specify which roles to assign using the role name, such as AM_DEFAULT_USER.
Tip
You can narrow the response using application_code and account_id query parameters.
curl -X GET "https://demo.one.digicert.com/account/api/v1/role?application_code=account_manager&account_id=ACCOUNT_ID" \
-H "x-api-key: SERVICE_API_TOKEN" \
-H "Content-Type: application/json"
Step 3: Create the service user
Service users require four fields in the request body:
friendly_nameto identify the service user.email_addressfor notifications.account_idfor association.rolesfor permissions and manager access.
After gathering those details, make a POST request to the /account/api/v1/user endpoint.
Request:
curl -X POST \
https://demo.one.digicert.com/account/api/v1/user \
-H "x-api-key: ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"friendly_name": "API Integration Service User",
"email": "api-notifications@example.com",
"description": "Service user for certificate automation",
"accounts": ["YOUR_ACCOUNT_ID"],
"roles": ["AM_DEFAULT_USER"]
}'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
ADMIN_API_TOKEN = "ADMIN_API_TOKEN"
# User details
FRIENDLY_NAME = "API Integration Service User"
EMAIL = "api-notifications@example.com"
DESCRIPTION = "Service user for certificate automation"
ACCOUNT_ID = "ACCOUNT_ID"
# Create service user
payload = {
"friendly_name": FRIENDLY_NAME,
"email": EMAIL,
"description": DESCRIPTION,
"accounts": [ACCOUNT_ID],
"roles": ["AM_DEFAULT_USER"]
}
response = requests.post(
f"{BASE_URL}/account/api/v1/user",
headers={
"x-api-key": ADMIN_API_TOKEN,
"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;
import com.fasterxml.jackson.databind.node.ArrayNode;
public class Example {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String adminApiToken = "ADMIN_API_TOKEN";
// User details
String friendlyName = "API Integration Service User";
String email = "api-notifications@example.com";
String description = "Service user for certificate automation";
String accountId = "ACCOUNT_ID";
// Build JSON payload
ObjectMapper mapper = new ObjectMapper();
ObjectNode payload = mapper.createObjectNode();
payload.put("friendly_name", friendlyName);
payload.put("email", email);
payload.put("description", description);
ArrayNode accounts = mapper.createArrayNode();
accounts.add(accountId);
payload.set("accounts", accounts);
ArrayNode roles = mapper.createArrayNode();
roles.add("AM_DEFAULT_USER");
payload.set("roles", roles);
// Create service user
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/account/api/v1/user"))
.header("x-api-key", adminApiToken)
.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;
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 adminApiToken = "ADMIN_API_TOKEN";
// User details
string friendlyName = "API Integration Service User";
string email = "api-notifications@example.com";
string description = "Service user for certificate automation";
string accountId = "ACCOUNT_ID";
// Build JSON payload
var payload = new JsonObject
{
["friendly_name"] = friendlyName,
["email"] = email,
["description"] = description,
["accounts"] = new JsonArray { accountId },
["roles"] = new JsonArray { "AM_DEFAULT_USER" }
};
// Create service user
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", adminApiToken);
var content = new StringContent(
payload.ToJsonString(),
Encoding.UTF8,
"application/json"
);
var response = await client.PostAsync(
$"{baseUrl}/account/api/v1/user",
content
);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Successful response (200 OK):
{
"id": "5e0bd5fe-117f-4049-b686-1548b1ee5e14",
"email": "api-notifications@example.com",
"status": "ACTIVE",
"access_scope": "account",
"primary_account_id": "449922b5-aad9-4e5b-9025-2bd0daf3619e",
"created_at": "2025-10-15T15:40:20Z",
"friendly_name": "API Integration Service User",
"description": "Service user for certificate automation",
"api_token": {
"id": "cdfcf47d-b47f-4919-bd1b-c62935312cea",
"user_id": "5e0bd5fe-117f-4049-b686-1548b1ee5e14",
"name": "API Integration Service User",
"token": "bedda3cd381bdfc8b17e10a0bfe350340cc4502c4ea9f41c3230ca6f8a17e97b7faa180727952e31fa1fe3227b2",
"enabled": true
},
"accounts": [
{
"id": "449922b5-aad9-4e5b-9025-2bd0daf3619e",
"name": "Demo Account",
"active": true
}
],
"applications": [
{
"id": "68e8e9fa-01cf-468f-9aae-f8b3b915f9c3",
"name": "Account Manager",
"permissions": ["VIEW_AM_ACCOUNT", "VIEW_AM_USER"]
}
]
}
Important
Theapi_token.token value is displayed only once during creation. Securely store it immediately. There is no way to retrieve it later.Step 4: Make your first authenticated request
Test the service user’s access by using the /account/api/v1/user/me endpoint.
Request:
curl -X GET https://demo.one.digicert.com/account/api/v1/user/me \
-H "x-api-key: SERVICE_API_TOKEN" \
-H "Content-Type: application/json" | jq '.'import requests
# Configuration
BASE_URL = "https://demo.one.digicert.com"
SERVICE_API_TOKEN = "SERVICE_API_TOKEN"
# Get current user details
response = requests.get(
f"{BASE_URL}/account/api/v1/user/me",
headers={
"x-api-key": SERVICE_API_TOKEN,
"Content-Type": "application/json"
}
)
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;
public class Example {
public static void main(String[] args) throws Exception {
// Configuration
String baseUrl = "https://demo.one.digicert.com";
String serviceApiToken = "SERVICE_API_TOKEN";
// Get current user details
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/account/api/v1/user/me"))
.header("x-api-key", serviceApiToken)
.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 serviceApiToken = "SERVICE_API_TOKEN";
// Get current user details
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", serviceApiToken);
client.DefaultRequestHeaders.Add("Content-Type", "application/json");
var response = await client.GetAsync(
$"{baseUrl}/account/api/v1/user/me"
);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine(responseBody);
}
}Common errors and solutions
{
"errors": [
{
"code": "AUTHORIZATION_ERROR",
"message": "No authentication data provided"
}
]
}
Make sure you include a valid API token with your request using the `x-api-key` header.{
"errors": [
{
"code": "no_access",
"message": "Not enough permissions"
}
]
}
Make sure your API token has appropriate roles and permissions.{
"errors": [
{
"code": "invalid_input_field",
"message": "Wrong input or input format"
}
]
}
Check endpoint specifications for valid field values.
Check your request body and validate your JSON.{
"errors": [
{
"code": "duplicate_error",
"message": "Nickname [name] already exists. Enter a different nickname."
}
]
}
Use a different value for the specified field.