TrueSign uses envelopes as a container for the documents that are being uploaded to be signed in TrueSign. An envelope belongs to an Envelope Type, an object configured by the TrueSign administrator in the Admin View of the TrueSign application.

Asynchronous Signing#

Asynchronous signing is intended for signing outside of your system, directly from TrueSign.com. An envelope is created in TrueSign and the user required to sign it can do so at their leisure. Once the required signer has completed an envelope, TrueSign will send a message via a service bus to your system. The message will contain the JSON data of the envelope (everything except the actual document bytes). Once a message has been received, you will have to download the file content from the provided URLs for each document in the envelope.

External Signing#

External signing is like asynchronous signing, but intended for signers outside of your organization. When creating an external envelope, you will provide the full name and the email address of the required external signer.

Note: External Signing module is required for your TrueSign subscription to be able to send an envelope to an external signer.

Interactive Signing#

Interactive signing is intended for scenarios when a user would like to upload a document to TrueSign and sign it right away, from the integration application. In this case:

  1. An envelope is created via the API
  2. Documents are added to the envelope
  3. The user is redirected to the TrueSign Viewer while the application waits
    • The user completes the envelope
  4. You retrieve the envelope by calling the API with the envelope ID returned from step 1
  5. You download the file content for each file in the envelope All these steps are managed by the application you are using/building to integrate with TrueSign.

Creating a new envelope#

When creating a new envelope, you have the option to send the document list on the same call or you can add the document list after the envelope has been created, but before it has been sent. The minimal fields required to create a new envelope is the title for the new envelope.

Note: You must have received a an authorization token before creating a new envelope and the token must be in the header of the request.

/*
    token => the JWT token received from the Authenticate call
    title => the title for the new envelope
*/
public static Guid CreateEnvelope(string token, string email, string title)
{
    using(var httpClient = new HttpClient())
    {
        //Set the base address for the client
        httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

        //add the authorization token to the httpClient's header
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        //JSON encode the body
        var json = JsonConvert.SerializeObject(new Dictionary<string, string>() { { "title", title } });
        var body = new StringContent(json, Encoding.UTF8, "application/json");

        //Make a POST call to the envelope endpoint of the API
        var response = httpClient.PostAsync("envelope", body).Result;

        //Ensure the call did not error out. If it did error out, then this will throw an exception.
        response.EnsureSuccessStatusCode();

        //Read the API's response into a dynamic object and return the new envelope ID to the caller.
        var new_envelope = response.Content.ReadAsStringAsync().Result;
        dynamic envelope = JsonConvert.DeserializeObject(new_envelope);
        return envelope.Id;
    }
}

Adding a Contact#

When creating a new envelope for an external signer, you may choose to add a contact to the envelope. The contact information will be sent to the signer in the email that notifies them of a new envelope. This information is intended to help the signer with any questions they have pertaining to the documents they are asked to sign. The contact object is sent in the body of the create envelope request, and the JSON object looks like this:

  "Contact": {
    "First_Name": "string",
    "Last_Name": "string",
    "Title": "string",
    "Email": "string",
    "Phone": "string"
  }

Note: You may choose to populate only certain fields of the contact object, and the email will only include those fields.

About Client Data#

When creating a new envelope, TrueSign gives you the ability to store any content up to 10'000 characters that will follow the envelope object in its whole trip. This data could be used by your custom application once the signed envelope has been downloaded to determine next steps for your workflow.

The Envelope Object#

Here is the full envelope object represented in JSON:

{
  "Id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "Type_Id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "Title": "string",
  "Status": 0,
  "TS_Account_Id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "Content": {
    "API_Version": 0,
    "Title": "string",
    "Url": "string",
    "Signers": [
      {
        "User_Id": "string",
        "Type": 0,
        "First_Name": "string",
        "Last_Name": "string",
        "Full_Name": "string",
        "Email": "string",
        "Code": {
          "Description": "string",
          "Value": "string"
        },
        "Completed": true,
        "Rejected": true,
        "Notify": true,
        "Reject_Reason": "string",
        "Consent": "string"
      }
    ],
    "Contact": {
      "First_Name": "string",
      "Last_Name": "string",
      "Title": "string",
      "Email": "string",
      "Phone": "string"
    },
    "Created_On_UTC": "2020-07-02T13:47:45.658Z",
    "Client_Data": "string",
    "Delivery_Method_Override": 0,
    "Documents": [
      {
        "Id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "Title": "string",
        "Upload_Url": "string",
        "Download_Url": "string",
        "Signed": true,
        "Stamped": true,
        "Client_Data": "string",
        "History": [
          {
            "Date_Time_UTC": "2020-07-02T13:47:45.658Z",
            "Message": "string",
            "Email": "string"
          }
        ]
      }
    ],
    "History": [
      {
        "DateTime_UTC": "2020-07-02T13:47:45.658Z",
        "History_Type": 0,
        "Message": "string"
      }
    ]
  }
}


Adding a signer#

After an envelope has been created and before the "Send" endpoint of the API has been called, you need to add a required signer for the envelope. Depending on your TrueSign subscription, there are two types of signers in TrueSign:

  • Internal - A user that has been invited to your organization and has a login in TrueSign.
  • External - A user that you invite to sign a particular envelope irregularly.

Note: External Signing module is required for your TrueSign subscription to be able to send an envelope to an external signer.

Internal Signer Example:

/*
    token => the JWT token received from the Authenticate call
    id => the envelope ID to which the signer is being added to
    email => the email for the internal signer.
*/
public static bool AddInternalSigner(string token, Guid id, string email)
{
    using(var httpClient = new HttpClient())
    {
        //Set the base address for the client
        httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

        //add the authorization token to the httpClient's header
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        //JSON encode the body
        var json = JsonConvert.SerializeObject(new Dictionary<string, string>() { { "email", email } });
        var body = new StringContent(json, Encoding.UTF8, "application/json");

        //Make a POST call to the envelope endpoint of the API
        var response = httpClient.PostAsync($"envelope/{id}/addinternalsigner", body).Result;

        //Ensure the call did not error out. If it did error out, then this will throw an exception.
        response.EnsureSuccessStatusCode();

        //If you have made it so far, everything went well
        return true;
    }
}

External Signer Example:

/*
    token => the JWT token received from the Authenticate call
    id => the envelope ID to which the signer is being added to
    email => the email for the external signer.
    first => the legal first name for the external signer.
    last => the legal last for the external signer.
*/
public static bool AddExternalSigner(string token, Guid id, string email, string first, string last)
{
    using(var httpClient = new HttpClient())
    {
        //Set the base address for the client
        httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

        //add the authorization token to the httpClient's header
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        //JSON encode the body
        var json = JsonConvert.SerializeObject(new Dictionary<string, string>() { { "email", email }, { "first_name", first }, { "last_name", last } });
        var body = new StringContent(json, Encoding.UTF8, "application/json");

        //Make a POST call to the envelope endpoint of the API
        var response = httpClient.PostAsync($"envelope/{id}/addexternalsigner", body).Result;

        //Ensure the call did not error out. If it did error out, then this will throw an exception.
        response.EnsureSuccessStatusCode();

        //If you have made it so far, everything went well
        return true;
    }
}


Adding documents to a TrueSign envelope#

After an envelope has been created, it is time to add documents to it! When adding documents via the API, you are only submitting the metadata for the document. The actual byte array of the document will be posted to a URL returned after a document has been successfully added to the open envelope.

The following method shows an example of adding a list of document objects to an existing TrueSign envelope. The method takes in the envelope id that has already been created; the token that was received from the GetToken() method and a list of document objects.

/*
    token => the JWT token received from the Authenticate call
    id => the envelope ID to which the documents are being added to
    docs => a list of document objects.
*/
public static JArray AddDocs(string token, Guid id, List<object> docs)
{
    using(var httpClient = new HttpClient())
    {
        //Set the base address for the client
        httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

        //add the authorization token to the httpClient's header
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        //Convert the TrueSign document list to JSON
        var json = JsonConvert.SerializeObject(docs);
        var body = new StringContent(json, Encoding.UTF8, "application/json");

        //Upload the JSON body the envelope
        var response = _Http_Client.PostAsync(string.Format("envelope/{0}/files", id), body).Result;

        //Ensure the call did not error out. If it did error out, then this will throw an exception.
        response.EnsureSuccessStatusCode();

        //Read the response of the API and deserialize it to a dynamic object
        var docs_resp = response.Content.ReadAsStringAsync().Result;
        dynamic new_docs = JsonConvert.DeserializeObject(docs_resp);

        //Return the list of the documents created, which now have an Upload_Url 
        //for you to upload the actual document bytes
        return new_docs;
    }
}

The Document Object#

Here is the document object represented in JSON:

{
  "Id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "Title": "string",
  "Upload_Url": "string",
  "Download_Url": "string",
  "Signed": true,
  "Stamped": true,
  "Client_Data": "string",
  "History": [
    {
      "Date_Time_UTC": "2020-07-02T14:05:17.181Z",
      "Message": "string",
      "Email": "string"
    }
  ]
}

Note: Only the title is required when uploading new documents to an envelope.


Uploading file content#

After this step, you still need to upload the document bytes to the Upload_Url returned by TrueSign from the last method. The document object has a Client_Data (string) parameter for you to store the ID of the document in your system (or any other data that you need for this document). If a Client_Data was saved when the document object was created, you can iterate through the list of documents returned from the AddDocs() method, retrieve the file content for each document and post it to the Upload_Url var of the document object:

public static void UploadDocs(List<object> new_docs)
{
    //Iterate through the list of TrueSign documents
    foreach(var doc in new_docs)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            ms = GET_FILE_CONTENT_STREAM //mySystem.getFileById(x=> x.Id == doc.Client_Data)

            //Post the stream of the document to the upload URL
            using (var client = new HttpClient())
            {
                var content = new ByteArrayContent(ms.ToArray());
                content.Headers.Add("x-ms-blob-type", "BlockBlob");
                var response = client.PutAsync(url, content).Result;

                //Ensure the call did not error out. If it did error out, then this will throw an exception.
                response.EnsureSuccessStatusCode();
            }
        }
    }
}


Sending an envelope#

By sending an envelope, you are marking it ready for the user to sign it and triggering background processes like notifying the user that a new envelope is ready for them to sign.

Note: Once an envelope has been marked as Ready to Sign, you may not add additional documents to it. However, you can still delete the envelope by using the API or the admin view in the TrueSign application.

To send an envelope, you make a single Get request to the TrueSign API with the envelope ID as a route parameter:

public static bool SendEnvelope(string token, Guid id)
{
    using (var httpClient = new HttpClient())
    {
        //Set the base address for the client
        httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

        //add the authorization token to the httpClient's header
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);


        //Call the send endpoint of the API
        var response = httpClient.GetAsync($"envelope/{id}/send").Result;

        //Ensure the call did not error out. If it did error out, then this will throw an exception.
        response.EnsureSuccessStatusCode();
    }
    return true;
}

Note: Depending on the user preferences, an internal user could receive an SMS or email with a link to the envelope for them to sign. An external user will always receive an email.


Downloading an envelope#

There are two ways to download a TrueSign envelope, depending on the delivery method for the envelope type that the envelope has been created under. The first option is for interactive envelopes, where the client needs to call TrueSign and request the completed envelope. The second option is for envelopes created under envelope types where the delivery method is set to ImageSoft Service Bus. This option requires implementing code to listen to an Azure Service Bus for messages that TrueSign sends to let the client know that an envelope has been completed and it is ready to be downloaded.

Downloading interactive envelopes#

To download an envelope that was created under a synchronous envelope type, you need to make a Get call to the TrueSign API with the TrueSign Envelope ID in the route of the call. This call will return an envelope object. You should always check the status of the envelope to make sure it is in the correct status for you to proceed with the business logic.

public static object GetEnvelope(string token, Guid id)
{
    try
    {
        using(var httpClient = new HttpClient())
        {
            //Set the base address for the client
            httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

            //add the authorization token to the httpClient's header
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            //Call the GET method of the API for the envelope
            var response = httpClient.GetAsync(string.Format("envelope/{0}", id)).Result;

            //Ensure the call did not error out. If it did error out, then this will throw an exception.
            response.EnsureSuccessStatusCode();

            //Read the JSON response and convert it to a dynamic object
            var envelopeTxt = response.Content.ReadAsStringAsync().Result;
            dynamic envelope = JsonConvert.DeserializeObjec(envelopeTxt);
            return envelope;
        }
    }
    catch (Exception ex)
    {
        //An error has occurred. Return null.
        //Handle exception here
        return null;
    }
}

Downloading asynchronous envelopes#

Envelopes that are created under an envelope type with ImageSoft Service Bus delivery method need to implement an Azure Service Bus listener and tune in to receive messages from TrueSign when an envelope is ready to be downloaded. For the connection string to the service bus, please go to app.truesign.com -> Admin View -> Envelope Types and click "Details" for the envelope type you are working with.

Here is a simple service bus listener (using a console app, taken from GitHub):

using Newtonsoft.Json;
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.ServiceBus;
using System.Threading;

class Program
{
    static string serviceBusConnectionString = "MY_SERVICE_BUS_CONNECTION_STRING";
    static IQueueClient queueClient;

    static void Main(string[] args)
    {
        MainAsync().GetAwaiter().GetResult();
    }

    static async Task MainAsync()
    {
        var csb = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
        queueClient = new QueueClient(csb);

        Console.WriteLine("======================================================");
        Console.WriteLine("Press any key to exit after receiving all the messages.");
        Console.WriteLine("======================================================");

        // Register QueueClient's MessageHandler and receive messages in a loop
        RegisterOnMessageHandlerAndReceiveMessages();

        Console.ReadKey();

        await queueClient.CloseAsync();
    }

    static void RegisterOnMessageHandlerAndReceiveMessages()
    {
        // Configure the MessageHandler Options in terms of exception handling, number of concurrent messages to deliver etc.
        var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler)
        {
            // Maximum number of Concurrent calls to the callback `ProcessMessagesAsync`, set to 1 for simplicity.
            // Set it according to how many messages the application wants to process in parallel.
            MaxConcurrentCalls = 1,

            // Indicates whether MessagePump should automatically complete the messages after returning from User Callback.
            // False below indicates the Complete will be handled by the User Callback as in `ProcessMessagesAsync` below.
            AutoComplete = false
        };

        // Register the function that will process messages
        queueClient.RegisterMessageHandler(ProcessMessagesAsync, messageHandlerOptions);
    }

    static async Task ProcessMessagesAsync(Message message, CancellationToken token)
    {
        // Process the message
        dynamic envelope = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(message.Body));

        //TO DO: do something with the received envelope.



        // Complete the message so that it is not received again.
        await queueClient.CompleteAsync(message.SystemProperties.LockToken);
    }

    // Use this Handler to look at the exceptions received on the MessagePump
    static Task ExceptionReceivedHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs)
    {
        Console.WriteLine($"Message handler encountered an exception {exceptionReceivedEventArgs.Exception}.");
        var context = exceptionReceivedEventArgs.ExceptionReceivedContext;
        Console.WriteLine("Exception context for troubleshooting:");
        Console.WriteLine($"- Endpoint: {context.Endpoint}");
        Console.WriteLine($"- Entity Path: {context.EntityPath}");
        Console.WriteLine($"- Executing Action: {context.Action}");
        return Task.CompletedTask;
    }
}

Downloading the signed documents#

Once an envelope has been downloaded using one of the above methods, the envelope object returned contains a list of documents. Each document object has a "Download_Url" string that you will use to download the actual signed file back into your system. The Client_Data parameter should be the ID to relate the TS_Document object with the document in your system. Remember to check if the document has actually been signed or stamped!

Note: This method will return a path to a temp file where the downloaded document is saved. The temp file should be deleted once the download has succeeded.

public static string DownloadFile(string url)
{
    try
    {
        using (var httpClient = new HttpClient())
        {
            //Get temp file path
            var path = Path.GetTempFileName();

            //Download the byte content from the URL
            var content = httpClient.GetByteArrayAsync(new Uri(url)).Result;

            //Write to the temp file
            File.WriteAllBytes(path, content);

            //Return the temp file path
            return path;
        }
    }
    catch (Exception ex)
    {
        //An error has occurred. Return null.
        //Handle exception here
        return null;
    }
}


Other envelope operations#

Besides creating, adding files, closing and downloading an envelope, the TrueSign also provides the following methods to be used as needed:

Get users for envelope type#

This method allows you to get a list of all users for your account. It will return the users full name and their email address. This could be used in a scenario where you are prompting the user creating a new envelope to select the required signer from the list.

public JArray GetUsers(string token)
{
    try
    {   
        using(var httpClient = new HttpClient())
        {
            //Set the base address for the client
            httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

            //add the authorization token to the httpClient's header
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            //Call the users endpoint and make sure the response is success.
            var response = httpClient.GetAsync("envelope/Users").Result;

            //Ensure the call did not error out. If it did error out, then this will throw an exception.
            response.EnsureSuccessStatusCode();

            //Read the successful response and convert it to a list of TS_Users
            var users_resp = response.Content.ReadAsStringAsync().Result;
            dynamic users = JsonConvert.DeserializeObject(users_resp);
            return users;
        }
    }
    catch (Exception ex)
    {
        //An error has occurred. Return null.
        //Handle exception
        return null;
    }
}

A user object is represented by the following JSON:

{
    "Email": "string",
    "Name": "string"
}

Get all envelopes#

This method allows you to get all envelopes for the authenticated envelope type. This will return all envelopes, no matter what status they are in.

public JArray GetAllEnvelopes(string token)
{
    try
    {   
        using(var httpClient = new HttpClient())
        {
            //Set the base address for the client
            httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

            //add the authorization token to the httpClient's header
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            //Call the envelope endpoint and make sure the response is success.
            var response = httpClient.GetAsync("envelope").Result;

            //Ensure the call did not error out. If it did error out, then this will throw an exception.
            response.EnsureSuccessStatusCode();

            //Read the successful response and convert it to a list of TS_Envelope
            var env_resp = response.Content.ReadAsStringAsync().Result;
            dynamic envelopes = JsonConvert.DeserializeObject(env_resp);

            return envelopes;
        }
    }
    catch (Exception ex)
    {
        //An error has occurred. Return null.
        //Handle exception
        return null;
    }
}

Delete an envelope#

If you need to delete an envelope via the API, you may do so by submitting a Delete call to the envelope endpoint:

public bool DeleteEnvelope(string token, Guid id)
{
    try
    {   
        using(var httpClient = new HttpClient())
        {
            //Set the base address for the client
            httpClient.BaseAddress = new Uri("https://api.truesign.com/v1/");

            //add the authorization token to the httpClient's header
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            //Call the envelope endpoint and make sure the response is success.
            var response = httpClient.DeleteAsync("envelope/" + id).Result;

            //Ensure the call did not error out. If it did error out, then this will throw an exception.
            response.EnsureSuccessStatusCode();

            //If you made it this far, everything went fine
            return true;
        }
    }
    catch (Exception ex)
    {
        //An error has occurred. Return false.
        //Handle exception
        return false;
    }
}

Envelope status#

A TrueSign envelope can be in any of the following statuses:

public enum Envelope_Status
{
    /// <summary>
    /// Envelope is created and ready to receive files.
    /// </summary>
    Created,

    /// <summary>
    /// Envelope has received all files, has been 
    /// closed and is ready to be signed.
    /// </summary>
    ReadyToSign,

    /// <summary>
    /// All files have been signed for this envelope.
    /// </summary>
    Signed,

    /// <summary>
    /// If Async Env Type, this is the status to mark the 
    /// envelope to send a message to the service bus.
    /// </summary>
    ReadyToNotify,

    /// <summary>
    /// A message was sent to the service bus (when async), 
    /// or the file was downloaded via the API (when sync).
    /// </summary>
    Completed,

    /// <summary>
    /// The envelope has been deleted.
    /// </summary>
    Deleted,

    /// <summary>
    /// This envelope has been rejected by the signer.
    /// </summary>
    Rejected
}