From the Trenches: May I see your ID?

When building your DocuSign integration, you will likely need to implement a step where you query DocuSign to verify that a given email address matches an active user in your account with permission to send envelopes. The DocuSign permission profiles necessary for sending envelopes are DS Sender or DS Admin, or "Send Envelopes" permission on a custom profile. In Developer Support we’ve noticed that some integration owners are making the Users:list call to get all active users on an account. Not only is this inefficient, but it can also cause some problems based on the number of users on an account. On June 15, 2021 a change took effect in eSignature REST API v 2.0 to restrict the max count of users returned by the GET Users:list from all users to 500. In v2.1 we limited the max count of users returned to 100. When DocuSign doesn’t return the user you are looking for, that can cause some issues.

Problem statement:

When making a Users:list call, we have seen developers encounter the following error in their own application because they can’t find the user they are querying for, even though the user exists in DocuSign.

  • Error while retrieving the UserID for the following sender: example@email.com
  • Your email is invalid

Recommended solution:

Query only for the one user you care about. The Users:list call supports the email query parameter in addition to status, so you can search specifically for the user in question to find their active membership. Check whether the user returned is active (userStatus=Active) and has permission to send (permissionProfileName=DS Admin || permissionProfileName=DS Sender). If using custom permission profiles, you’ll need to check for the "Send Envelopes" permission; else, return the appropriate exception.

Endpoint: GET /restapi/v2.1/accounts/{accountId}/users/?email=user@example.com

C# sample code to get a single user:

public static void GetUserByEmail() {
    String email = "user@example.com";
    String accountId = "12345678";

    //ConfigureApiClient() code is not shown.
    //This method instantiates an apiClient and uses JWT to configure default authentication headers
    ApiClient apiClient = new ConfigureApiClient();
    UsersApi usersApi = new UsersApi(apiClient);
    UsersApi.ListOptions options = new UsersApi.ListOptions();
    options.email = email;
    UserInformationList response = usersApi.List(accountId, options);
    Console.WriteLine(response.Users[0].ToString());
}

JSON response: 

{
    "users": [
        {
            "userName": "Zack Silverman",
            "userId": "bff9e3ae-xxxx-xxxx-xxxx-40341ace7294",
            "userType": "CompanyUser",
            "isAdmin": "True",
            "isAlternateAdmin": "False",
            "userStatus": "Active",
            "uri": "/users/bff9e3ae-xxxx-xxxx-xxxx-40341ace7294",
            "email": "user@example.com",
            "title": "",
            "createdDateTime": "2022-05-01T19:23:06.2270000Z",
            "userAddedToAccountDateTime": "2022-05-01T19:23:06.2270000Z",
            "firstName": "Zack",
            "middleName": "",
            "lastName": "Silverman",
            "suffixName": "",
            "jobTitle": "Developer Support Engineer",
            "company": "DocuSign",
            "permissionProfileId": "12345678",
            "permissionProfileName": "Account Administrator"
        }
    ],
    "resultSetSize": "1",
    "totalSetSize": "1",
    "startPosition": "0",
    "endPosition": "0"
}

Alternate solution:

The Users:List call supports paging. When your account contains more users than the maximum number allowed in a single call response, not only does the response include that maximum number of users, but the nextUri attribute in the response object includes parameters, including start_position and count, that can be used to make another call for the next page of users.

If you use paging to get a full list of users for your account, I would recommend caching the resulting user IDs in your application. Constantly polling the list of users is an inefficient call pattern. You can reduce the volume of API traffic your integration generates dramatically by only checking the API for the user if they don't have a user ID already cached in your database, or if there is an error while attempting to send an envelope.

How to get all users:

Endpoint: GET /restapi/v2.1/accounts/{accountId}/users

C# sample code to get all users:

Note: The version of the eSignature REST API you’re querying dictates the maximum number of users returned: 500 for v2.0, and 100 for v2.1.

GetAllUsers("0");

public static void GetAllUsers(String startPos)
{
    String accountId = "12345678";

    //ConfigureApiClient() code is not shown.
    //This method instantiates an apiClient and uses JWT to configure default authentication headers
    ApiClient apiClient = new ConfigureApiClient();

    UsersApi usersApi = new UsersApi(apiClient);
    UsersApi.ListOptions options = new UsersApi.ListOptions();
    options.count = "5"; //set users being returned to control paging
    options.startPosition = startPos;
    UserInformationList response = usersApi.List(accountId,options);
    var endPos = response.EndPosition; //initialize total users 

    // prints email of each user for the first 5 users 
    foreach (var item in response.Users)
    {
        Console.WriteLine(item.Email.ToString());
    }

    // loops through recursively to get all users
    while (int.Parse(endPos) < int.Parse(response.TotalSetSize)-1)
    {
        var next = int.Parse(endPos)+1;
        endPos = recursiveStep(next.ToString(),apiClient,accountId);
    }

}

public static String recursiveStep(String startPos, ApiClient apiClient, String accountId)
{
    UsersApi usersApi = new UsersApi(apiClient);
    UsersApi.ListOptions options = new UsersApi.ListOptions();
    options.count = "5";
    options.startPosition = startPos;
    UserInformationList response = usersApi.List(accountId, options);

    // prints email of each user
    foreach (var item in response.Users)
    {
        Console.WriteLine(item.Email.ToString());
    }

    return response.EndPosition;
}

For testing this implementation in the DocuSign demo environment, you can set the count parameter to mock having multiple pages of users. Once you have this working in demo, feel free to go-live in production.

Additional resources

Zack Silverman
Author
Zack Silverman
Developer Support Engineer
Published