--- title: "Onboard a signer and issue a signing credential" description: "Create a signer and issue credentials for document signing.\n" source_url: https://dev.digicert.com/content-trust-api/tutorials/onboard-a-signer-and-issue-a-signing-credential.html --- Content 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 Content 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 **Content 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 | Method | Path | Description | |--------|------|-------------| | POST | /api/v1/user | Create a signer | | PUT | /api/v1/user/{userId} | Update signer details | | POST | /api/v2/credential | Create a credential | ## Step 1: Create a signer To onboard a new signer, create them as a Content 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** ```bash 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 '.' ``` **python** ```python 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()) ``` **Java** ```java 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 response = client.send( request, HttpResponse.BodyHandlers.ofString() ); System.out.println("Status Code: " + response.statusCode()); System.out.println(response.body()); } } ``` **C#** ```csharp 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`. > **Warning** > > For delegated account signers, set `is_pipl_accepted` and `is_tou_accepted` to `true`. ### Request fields | Field | Type | Required | Description | |-------|------|----------|-------------| | `user_name` | String | Yes | Signer username | | `email` | String | Yes | Signer email address | | `first_name` | String | Yes | First name | | `last_name` | String | Yes | Last name | | `user_type` | String | Yes | Use `standard` | | `description` | String | No | Description of the user | | `phone_number` | String | No | Contact number | | `accounts` | Array | Yes | DTM account IDs | | `locale` | String | No | Default: `en_US` | | `roles` | Array | Yes | Must include `DSM_DOCUMENT_SIGNER` | | `is_pipl_accepted` | Boolean | Yes | Indicates PIPL acceptance | | `is_tou_accepted` | Boolean | Yes | Indicates TOU acceptance | **Successful response (201 Created):** ```json { "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** ```bash 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" }' ``` **python** ```python 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()) ``` **Java** ```java 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 response = client.send( request, HttpResponse.BodyHandlers.ofString() ); System.out.println("Status Code: " + response.statusCode()); System.out.println(response.body()); } } ``` **C#** ```csharp 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** ```bash 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 '.' ``` **python** ```python 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()) ``` **Java** ```java 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 response = client.send( request, HttpResponse.BodyHandlers.ofString() ); System.out.println("Status Code: " + response.statusCode()); System.out.println(response.body()); } } ``` **C#** ```csharp 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`. > **Note** > > Adding a new contact creates a new authorized representative and triggers a new validation. **Successful response (201 OK):** ```json { "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.