Onboard a signer and issue a signing credential

Create a signer and issue credentials for document signing.

Document Trust Manager enables signers to digitally sign documents using API-managed credentials. These APIs replace the legacy validation-based workflow by letting you create signers directly and issue credentials as needed.

In this tutorial, you will:

  • Create a signer as a Document Trust Manager user.
  • Update the signer’s details.
  • Create a credential for the signer.

Before you begin

Before you begin, make sure you have:

A DigiCert ONE account with Document Trust Manager access.
A service user with API key authentication. For instructions, see Create a service user.

API token with the following permissions:

  • Permission to create and update users
  • Permission to create and manage credentials
  • Permission to access the required DigiCert ONE accounts
Your DigiCert ONE account ID (account_id).
Your organization ID (org_id) for credential creation in Step 3.

Endpoint overview

MethodPathDescription
POST/api/v1/userCreate a signer
PUT/api/v1/user/{userId}Update signer details
POST/api/v2/credentialCreate a credential

Step 1: Create a signer

To onboard a new signer, create them as a Document Trust Manager user. This step replaces the legacy flow where you had to create a validation first. The signer is created directly as a user and assigned the DSM_DOCUMENT_SIGNER role.

Request:

curl -X POST "https://demo.one.digicert.com/documentmanager/api/v1/user" \
  -H "x-api-key: SERVICE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user_name": "user1710238743839",
    "email": "james.demo.1@example.com",
    "first_name": "James",
    "last_name": "Smith",
    "user_type": "standard",
    "accounts": [
      "ACCOUNTS"
    ],
    "roles": [
      "DSM_DOCUMENT_SIGNER"
    ],
    "is_pipl_accepted": true,
    "is_tou_accepted": true,
    "description": "user created by api",
    "phone_number": "919999988888",
    "locale": "en_US"
  }' | jq '.'
import requests

# Configuration
BASE_URL = "https://demo.one.digicert.com"
SERVICE_API_TOKEN = "SERVICE_API_TOKEN"
# Request details
USER_NAME = "user1710238743839"
EMAIL = "james.demo.1@example.com"
FIRST_NAME = "James"
LAST_NAME = "Smith"
USER_TYPE = "standard"
DESCRIPTION = "user created by api"
PHONE_NUMBER = "919999988888"
LOCALE = "en_US"
ACCOUNTS = "ACCOUNTS"
DSM_DOCUMENT_SIGNER = "DSM_DOCUMENT_SIGNER"

payload = {
    "user_name": USER_NAME,
    "email": EMAIL,
    "first_name": FIRST_NAME,
    "last_name": LAST_NAME,
    "user_type": USER_TYPE,
    "accounts": [ACCOUNTS],
    "roles": [DSM_DOCUMENT_SIGNER],
    "is_pipl_accepted": True,
    "is_tou_accepted": True,
    "description": DESCRIPTION,
    "phone_number": PHONE_NUMBER,
    "locale": LOCALE,
}

response = requests.post(
    f"{BASE_URL}/documentmanager/api/v1/user",
    headers={
        "x-api-key": SERVICE_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 ApiExample {
    public static void main(String[] args) throws Exception {
        // Configuration
        String baseUrl = "https://demo.one.digicert.com";
        String serviceApiToken = "SERVICE_API_TOKEN";
        // Request details
        String userName = "user1710238743839";
        String email = "james.demo.1@example.com";
        String firstName = "James";
        String lastName = "Smith";
        String userType = "standard";
        String description = "user created by api";
        String phoneNumber = "919999988888";
        String locale = "en_US";

        // Build payload
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode payload = mapper.createObjectNode();
        payload.put("user_name", userName);
        payload.put("email", email);
        payload.put("first_name", firstName);
        payload.put("last_name", lastName);
        payload.put("user_type", userType);

        ArrayNode accountsArray = mapper.createArrayNode();
        accountsArray.add("ACCOUNTS");
        payload.set("accounts", accountsArray);

        ArrayNode rolesArray = mapper.createArrayNode();
        rolesArray.add("DSM_DOCUMENT_SIGNER");
        payload.set("roles", rolesArray);
        payload.put("is_pipl_accepted", true);
        payload.put("is_tou_accepted", true);
        payload.put("description", description);
        payload.put("phone_number", phoneNumber);
        payload.put("locale", locale);

        // Send request
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/documentmanager/api/v1/user"))
            .header("x-api-key", serviceApiToken)
            .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 serviceApiToken = "SERVICE_API_TOKEN";
        // Request details
        string userName = "user1710238743839";
        string email = "james.demo.1@example.com";
        string firstName = "James";
        string lastName = "Smith";
        string userType = "standard";
        string description = "user created by api";
        string phoneNumber = "919999988888";
        string locale = "en_US";

        // Build payload
        var payload = new JsonObject
        {
            ["user_name"] = userName,
            ["email"] = email,
            ["first_name"] = firstName,
            ["last_name"] = lastName,
            ["user_type"] = userType,
            ["accounts"] = new JsonArray { "ACCOUNTS" },
            ["roles"] = new JsonArray { "DSM_DOCUMENT_SIGNER" },
            ["is_pipl_accepted"] = true,
            ["is_tou_accepted"] = true,
            ["description"] = description,
            ["phone_number"] = phoneNumber,
            ["locale"] = locale
        };

        // Send request
        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("x-api-key", serviceApiToken);

        var content = new StringContent(
            payload.ToJsonString(),
            Encoding.UTF8,
            "application/json"
        );

        var response = await client.PostAsync($"{baseUrl}/documentmanager/api/v1/user", content);

        string responseBody = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Status Code: {(int)response.StatusCode}");
        Console.WriteLine(responseBody);
    }
}

Set user_type to standard. The roles array must include DSM_DOCUMENT_SIGNER.

Request fields

FieldTypeRequiredDescription
user_nameStringYesSigner username
emailStringYesSigner email address
first_nameStringYesFirst name
last_nameStringYesLast name
user_typeStringYesUse standard
descriptionStringNoDescription of the user
phone_numberStringNoContact number
accountsArrayYesDTM account IDs
localeStringNoDefault: en_US
rolesArrayYesMust include DSM_DOCUMENT_SIGNER
is_pipl_acceptedBooleanYesIndicates PIPL acceptance
is_tou_acceptedBooleanYesIndicates TOU acceptance

Successful response (201 Created):

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
}

From the response, save the id value. This is the signer’s user ID. You need this as the {userId} path parameter in Step 2 and the userId field in Step 3.

Step 2: Update the signer

After creating a signer, you can update their details if any information changes or was entered incorrectly. The account field with nested id is required for every update request.

Request:

curl -X PUT "https://demo.one.digicert.com/documentmanager/api/v1/user/USER_ID" \
  -H "x-api-key: SERVICE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "account": {
      "id": "account_id",
      "name": "name_value"
    },
    "email": "james.demo.1@example.com",
    "first_name": "James",
    "last_name": "Smith",
    "phone_number": "919999988888",
    "locale": "en_US"
  }'
import requests

# Configuration
BASE_URL = "https://demo.one.digicert.com"
SERVICE_API_TOKEN = "SERVICE_API_TOKEN"
USER_ID = "USER_ID"
# Request details
EMAIL = "james.demo.1@example.com"
FIRST_NAME = "James"
LAST_NAME = "Smith"
PHONE_NUMBER = "919999988888"
LOCALE = "en_US"

payload = {
    "account": {"id": "account_id", "name": "name_value"},
    "email": EMAIL,
    "first_name": FIRST_NAME,
    "last_name": LAST_NAME,
    "phone_number": PHONE_NUMBER,
    "locale": LOCALE,
}

response = requests.put(
    f"{BASE_URL}/documentmanager/api/v1/user/{USER_ID}",
    headers={
        "x-api-key": SERVICE_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;

public class ApiExample {
    public static void main(String[] args) throws Exception {
        // Configuration
        String baseUrl = "https://demo.one.digicert.com";
        String serviceApiToken = "SERVICE_API_TOKEN";
        String userId = "USER_ID";
        // Request details
        String email = "james.demo.1@example.com";
        String firstName = "James";
        String lastName = "Smith";
        String phoneNumber = "919999988888";
        String locale = "en_US";

        // Build payload
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode payload = mapper.createObjectNode();

        ObjectNode accountNode = mapper.createObjectNode();
        accountNode.put("id", "account_id");
        accountNode.put("name", "name_value");
        payload.set("account", accountNode);
        payload.put("email", email);
        payload.put("first_name", firstName);
        payload.put("last_name", lastName);
        payload.put("phone_number", phoneNumber);
        payload.put("locale", locale);

        // Send request
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/documentmanager/api/v1/user/" + userId))
            .header("x-api-key", serviceApiToken)
            .header("Content-Type", "application/json")
            .PUT(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 serviceApiToken = "SERVICE_API_TOKEN";
        string userId = "USER_ID";
        // Request details
        string email = "james.demo.1@example.com";
        string firstName = "James";
        string lastName = "Smith";
        string phoneNumber = "919999988888";
        string locale = "en_US";

        // Build payload
        var payload = new JsonObject
        {
            ["account"] = new JsonObject
            {
                ["id"] = "account_id",
                ["name"] = "name_value"
            },
            ["email"] = email,
            ["first_name"] = firstName,
            ["last_name"] = lastName,
            ["phone_number"] = phoneNumber,
            ["locale"] = locale
        };

        // Send request
        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("x-api-key", serviceApiToken);

        var content = new StringContent(
            payload.ToJsonString(),
            Encoding.UTF8,
            "application/json"
        );

        var response = await client.PutAsync($"{baseUrl}/documentmanager/api/v1/user/{userId}", content);

        string responseBody = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Status Code: {(int)response.StatusCode}");
        Console.WriteLine(responseBody);
    }
}

Replace {userId} with the signer’s user ID from Step 1.

Successful response (204 No Content):

A 204 response confirms the update was successful. No response body is returned.

Verify the update by retrieving the user details if needed.

Step 3: Create a credential

Once the signer exists, create a credential to enable document signing. This step also initiates the validation process automatically.

Request:

curl -X POST "https://demo.one.digicert.com/documentmanager/api/v2/credential" \
  -H "x-api-key: SERVICE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "productName": "AATL Electronic Seal | ZertES",
    "countryCode": "IN",
    "organization": {
      "id": "org_id",
      "contacts": []
    },
    "label": "tets3",
    "userId": "user_id"
  }' | jq '.'
import requests

# Configuration
BASE_URL = "https://demo.one.digicert.com"
SERVICE_API_TOKEN = "SERVICE_API_TOKEN"
# Request details
PRODUCT_NAME = "AATL Electronic Seal | ZertES"
COUNTRY_CODE = "IN"
LABEL = "tets3"
USER_ID = "user_id"

payload = {
    "productName": PRODUCT_NAME,
    "countryCode": COUNTRY_CODE,
    "organization": {"id": "org_id", "contacts": []},
    "label": LABEL,
    "userId": USER_ID,
}

response = requests.post(
    f"{BASE_URL}/documentmanager/api/v2/credential",
    headers={
        "x-api-key": SERVICE_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;

public class ApiExample {
    public static void main(String[] args) throws Exception {
        // Configuration
        String baseUrl = "https://demo.one.digicert.com";
        String serviceApiToken = "SERVICE_API_TOKEN";
        // Request details
        String productName = "AATL Electronic Seal | ZertES";
        String countryCode = "IN";
        String label = "tets3";
        String userId = "user_id";

        // Build payload
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode payload = mapper.createObjectNode();
        payload.put("productName", productName);
        payload.put("countryCode", countryCode);

        ObjectNode organizationNode = mapper.createObjectNode();
        organizationNode.put("id", "org_id");

        ArrayNode contactsArray = mapper.createArrayNode();
        organizationNode.set("contacts", contactsArray);
        payload.set("organization", organizationNode);
        payload.put("label", label);
        payload.put("userId", userId);

        // Send request
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(baseUrl + "/documentmanager/api/v2/credential"))
            .header("x-api-key", serviceApiToken)
            .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 serviceApiToken = "SERVICE_API_TOKEN";
        // Request details
        string productName = "AATL Electronic Seal | ZertES";
        string countryCode = "IN";
        string label = "tets3";
        string userId = "user_id";

        // Build payload
        var payload = new JsonObject
        {
            ["productName"] = productName,
            ["countryCode"] = countryCode,
            ["organization"] = new JsonObject
            {
                ["id"] = "org_id",
                ["contacts"] = new JsonArray {  }
            },
            ["label"] = label,
            ["userId"] = userId
        };

        // Send request
        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("x-api-key", serviceApiToken);

        var content = new StringContent(
            payload.ToJsonString(),
            Encoding.UTF8,
            "application/json"
        );

        var response = await client.PostAsync($"{baseUrl}/documentmanager/api/v2/credential", content);

        string responseBody = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Status Code: {(int)response.StatusCode}");
        Console.WriteLine(responseBody);
    }
}

Set productName to the signing product for your account. The organization object must include the organization id and a contacts array with at least one contact of type VERIFIED_CONTACT.

Successful response (201 OK):

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "status": "active"
}

The response includes credential identifiers, order details, and status. Save the credential name to use with the credential management APIs.