Direct Signi API call from Microsoft

Modified on Mon, 17 Jun at 7:40 PM


Direct Signi API call

The advantage of the Signi API direct call is flexibility, new Signi APIs are immediately available for use. It is possible to process multiple documents in parallel at once. It can be used from both cloud tenants and on premise installations. For calls from Microsoft Power Automate, HTTP and Webhook operations are used.


Before calling the API, you need to generate an API Key in the Signi application for the workspace / workspace to which you will be passing documents for signing, see Generating an API Key. You can then call any of the Signi API End Points.


The following examples show Signi API calls from three different Microsoft technologies

  1. Microsoft Power Automate,

  2. .NET code,

  3. code in Visual Basic for Application - VBA.


Example of a Signi API call from MS Power Automate 

MS Power Automate is an integration service that is part of the Microsoft Power Platform technology platform. The example Signi API call from MS Power Automate consists of three flows:

  • Signi Demo - Signing a document from a template- Invokes a signature on a document created from the "Test Agreement to Sign" template stored in Signi and made available in the Demo API test workspace,

  • Signi Demo - Sign PDF file - submits a PDF file for signature,

  • Signi Demo - Webhook - creates a webhook in the MS Power Automate environment to receive the results of the document signing, referenced by the first flow.


Example flow in MS Power Automate.


To try it out, it is on the Signi production workspace "Demo API" and has API key =  “71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f”, when making your calls, replace this API key with your workspace's API key, which you get by subscribing to the "API Integration" and API Key Generation services.


You can download the individual flows from the examples below here.


Creating a flow for signing a document from a template 

Create a new flow via MS Power Automate > Create (in the left panel) > Instant cloud flow (to run manually ) > Manually create flow.



Insert into flow operation via Next step > HTTP (select this operation type).



Parameters of the HTTP operation to invoke the pattern similarly as in Signi HELP > API Integration > Example 3 - Submitting the basis for the template : 

  • POST request

  • The EndPoint address is https://api.signi.com/api/v1/contract/?type=template

  • In the HEAD to authenticate the API key in the field named x-api-key 

  • For demo purposes, the Signi production environment is  https://api.signi.com is workspace "Demo API" and has API key = “71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f”, when making your calls, replace this API key with your workspace's API key, which you get by subscribing to the "API Integration" and API Key Generation services.

  • The body is the required JSON with all parameters to create the document, the url of the webhook corresponds to the webhook created below, can be added after testing this flow.

  • You can change the demo+counterparty@signi.com email to yours.


{
  "settings": {
    "signing_order": "proposers_before_counterparties",
    "autosign_proposers": "V Praze"
  },
  "people": [
    {
      "is_proposer": true,
      "email": "demo@signi.com",
      "contract_role": "sign"
    },
    {
      "is_proposer": false,
      "party_order": 1,
      "email": "demo+counterparty@signi.com",
      "contract_role": "sign",
      "person_type": "nature",
      "first_name": "John",
      "last_name": "Doe2"
    }
  ],
  "webhooks": [
    {
      "state": "completed",
      "url": "https://prod-174.westeurope.logic.azure.com:443/workflows/4255c88e046844319c27fdf997ee7eed/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=lJhO1j7pXPUUzQ6apYhS1TJmI6HoEyN4NS_cBMI-6rw"
    }
  ],
  "template": {
    "id": "7v1",
    "parameters": [
      {
        "id": "112",
        "value": "Hnutí za digitalní revoluci"
      },
      {
        "id": "131",
        "value": "Chci"
      },
      {
        "id": "411",
        "value": "V šíření zpráv"
      },
      {
        "id": "421",
        "value": "27.5.2021"
      },
      {
        "id": "431",
        "value": "v Praze"
      }
    ]
  }
}



Save flow via Save.



For testing, select Test and Run Flow.



The result of the Signi API response to a request accessed in MS Power Automate:



Create a flow for signing a PDF file 

Create a new flow via MS Power Automate > Create (in the left panel) > Instant cloud flow (to run manually ) > Manually create flow.


In the flow to sign a PDF file, you first need to get the file to sign into the flow, here we use the Get file content operator.



Then we call the HTTP operator again, HTTP operation parameters for calling the pattern similarly as in Signi HELP > API Integration > Example 2 - Passing a PDF document for signature

  • POST request

  • The EndPoint address is  https://api.signi.com/api/v1/contract/?type=doc

  • In the HEAD for authentication, the API key in the field named x-api-key 

  • For demo purposes, the Signi production environment is https://api.signi.com is workspace "Demo API" and has API key =  “71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f”, when making your calls, replace this API key with your workspace's API key, which you get by subscribing to the "API Integration" and API Key Generation services.

  • The body is the required JSON with all the parameters to create the document, the url of the webhook corresponds to the webhook created below, can be added after testing this flow.

  • You can change the demo+counterparty@signi.com email to yours.


{
  "$content-type": "multipart/form-data",
  "$multipart": [
    {
      "headers": {
        "Content-Disposition": "form-data; name=\"metadata\"; filename=\"data.json\""
      },
      "body": {
        "name": "test",
        "number": "123456",
        "locale": "cs",
        "webhooks": [
          {
            "state": "completed",
            "url": "https://prod-174.westeurope.logic.azure.com:443/workflows/4255c88e046844319c27fdf997ee7eed/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=lJhO1j7pXPUUzQ6apYhS1TJmI6HoEyN4NS_cBMI-6rw"
          }
        ],
        "settings": {
          "signing_order": "one_at_a_time",
          "missing_positions": "append_to_the_end"
        },
        "people": [
          {
            "is_proposer": true,
            "party_order": 1,
            "email": "demo@signi.com",
            "contract_role": "sign"
          },
          {
            "is_proposer": false,
            "party_order": 2,
            "email": "demo+counterparty@signi.com",
            "phone": "723653670",
            "first_name": "John",
            "last_name": "Doe#1",
            "contract_role": "sign",
            "person_type": "nature"
          }
        ],
        "file": "file_key"
      }
    },
    {
      "headers": {
        "Content-Disposition": "form-data; name=\"file_key\"; filename=\"test.pdf\""
      },
      "body": {
        "$content-type": "application/pdf",
        "$content": "@{body('Get_file_content')?['body']}"
      }
    }
  ]
}


in JSON we need to refer to the file obtained in the previous step , for this we use the dynamic File Content.


 

The next testing flow is the same as the flow for creating a document from a template.


Creating the flow for the webhook to receive the signing result 

Create a new flow via MS Power Automate in the left pane > Create > Instant cloud flow for manual execution > Manually create flow.  

Insert an operation into the flow via Next step > When an HTTP request is received (select this operation type).



JAs a template for the data that the webhook receives, you need to insert a JSON example, see the example at  https://signi.docs.apiary.io/#reference/webhooky/ze-vzoru-s-prilohami i.e,


{
    "type": "object",
    "properties": {
        "contract_id": {
            "type": "integer"
        },
        "state": {
            "type": "string"
        },
        "file": {
            "type": "string"
        },
        "attachments": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "contract_id": {
                        "type": "integer"
                    },
                    "state": {
                        "type": "string"
                    },
                    "file": {
                        "type": "string"
                    }
                },
                "required": [
                    "contract_id",
                    "state",
                    "file"
                ]
            }
        }
    }
}



JThe second is the Parse JSON operation embedded in the flow, which says that the code from the Body will be processed and takes what the webhook gets from Signi as an example JSON schema, see above. At the same time, the Copy icon gets the URL of the webhook, which is then filled in as a parameter to the Signi call in the first and second flow examples.



You can see the result of a webhook call in MS Power Automate in the flow history Signi Demo - webhook, on the detail page at the bottom view the history of the last call , where you can see the results of the call.





Code example in .NET 

.NET is Microsoft's framework for application development.

  • On the Signi production environment, the workspace is "Demo API" and has API key =  “71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f”, when making your calls, replace this API key with your workspace's API key, which you get by subscribing to the "API Integration" and API Key Generation services.

  • The RestSharp library, https://restsharp.dev/ is used to send HTTP requests.

  • Below are the calls to the various Signi API enpoints.


using Art.Gaia;
using Art.IDocuments.Models;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

using Newtonsoft.Json;

using RestSharp;

using System;
using System.Collections.Generic;
using System.Text;

using BE = Art.BusinessEntity;

namespace Art.IDocuments.Logic
{
    public class AnnotationLogic
    {
        public Base _base;
        public AnnotationLogic(Base myBase)
        {
            _base = myBase;
        }


// Upload From File 

        public string Upload(EntityReference dokumentReference)
        {
            try
            {
                BE.art_idokument dokument = _base.Service.Retrieve(BE.art_idokument.EntityLogicalName, dokumentReference.Id,
                    new ColumnSet(BE.art_idokument.Attr.art_customerid.LogicalName, BE.art_idokument.Attr.art_name.LogicalName, BE.art_idokument.Attr.art_sablonaid.LogicalName)).ToEntity<BE.art_idokument>();
                BE.art_idokumentsablona sablona = _base.Service.Retrieve(dokument.art_sablonaid.LogicalName, dokument.art_sablonaid.Id,
                    new ColumnSet(BE.art_idokumentsablona.Attr.art_emailautor.LogicalName, BE.art_idokumentsablona.Attr.art_mistopodpisu.LogicalName, BE.art_idokumentsablona.Attr.art_spolecnost.LogicalName, BE.art_idokumentsablona.Attr.art_stranapospisu.LogicalName)).ToEntity<BE.art_idokumentsablona>();
                BE.contact contact = _base.Service.Retrieve(BE.contact.EntityLogicalName, dokument.art_customerid.Id,
                    new ColumnSet(BE.contact.Attr.firstname.LogicalName, BE.contact.Attr.lastname.LogicalName, BE.contact.Attr.emailaddress1.LogicalName, BE.contact.Attr.mobilephone.LogicalName, BE.contact.Attr.address1_line1.LogicalName, BE.contact.Attr.description.LogicalName)).ToEntity<BE.contact>();
                QueryExpression queryAnno = new QueryExpression
                {
                    EntityName = BE.annotation.EntityLogicalName,
                    NoLock = true,
                    TopCount = 1,
                    ColumnSet = new ColumnSet(BE.annotation.Attr.filename.LogicalName, BE.annotation.Attr.mimetype.LogicalName, BE.annotation.Attr.documentbody.LogicalName),
                    Criteria = new FilterExpression(LogicalOperator.And)
                    {
                        Conditions =
                        {
                            new ConditionExpression(BE.annotation.Attr.objectid.LogicalName,ConditionOperator.Equal,dokument.Id)
                        }
                    }
                };
                List<BE.annotation> annotations = _base.Service.RetrieveMultiple<BE.annotation>(queryAnno);
                if (annotations.Count == 0) return "Žádné přílohy";
                BE.annotation anno = annotations[0];
                byte[] bytes = Convert.FromBase64String(anno.documentbody);
                if (anno.filename.Contains("html"))
                {
                    byte[] data = Convert.FromBase64String(anno.documentbody);
                    string decodedString = Encoding.UTF8.GetString(data);
                    string newBodyText = decodedString.Replace("{data_z_dynamics1}", contact.description).Replace("{data_z_dynamics2}", contact.address1_line1);
                    bytes = Encoding.UTF8.GetBytes(newBodyText);
                }

                // Dokument stažený z Dynamics 365 DB
                var client = new RestClient("https://api.signi.com/api/v1/contract/sign/provided")
                {
                    Timeout = -1
                };
                //client.UseNewtonsoftJson();
                var request = new RestRequest(Method.POST);
                //request.UseNewtonsoftJson();
                request.AddHeader("x-api-key", "71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f");
                request.AddHeader("Content-Type", "multipart/form-data");
                request.AddParameter("email_author", sablona.art_emailautor);
                request.AddParameter("email_signer", contact.emailaddress1);
                request.AddParameter("phone_signer", contact.mobilephone);
                request.AddParameter("firstname_signer", contact.firstname);
                request.AddParameter("lastname_signer", contact.lastname);
                request.AddParameter("proposer_sign", "true");
                request.AddParameter("negotiator_sign", "true");
                request.AddParameter("contract_name", dokument.art_name);
                request.AddParameter("contract_number", dokument.art_cislodokumentu);
                request.AddParameter("sign_date", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
                request.AddParameter("sign_place", sablona.art_mistopodpisu);
                request.AddParameter("last_document", "true");
                request.AddParameter("person_type", "legal");
                //request.AddParameter("date_of_birth", "1970-04-16");
                //request.AddParameter("street", "5. května 67");
                //request.AddParameter("city", "Libčice nad Vltavou");
                //request.AddParameter("zip_code", "25266");
                request.AddParameter("company_name", sablona.art_spolecnost);
                //request.AddParameter("ic", "28524322");
                //request.AddParameter("dic", "CZ28524322");
                //request.AddParameter("sign_proposer", "{\"position\": {\"x\": 15,\"y\": 84,\"page\": 0}}");
                //request.AddParameter("sign_negotiator", "{\"position\": {\"x\": 78,\"y\": 84,\"page\": 0}}");
                request.AddParameter("sign_proposer[position][x]", 8);
                request.AddParameter("sign_proposer[position][y]", 84);
                request.AddParameter("sign_proposer[position][page]", sablona.art_stranapospisu - 1);
                request.AddParameter("sign_negotiator[position][x]", 64);
                request.AddParameter("sign_negotiator[position][y]", 84);
                request.AddParameter("sign_negotiator[position][page]", sablona.art_stranapospisu - 1);
                request.AddParameter("webhooks[0][state]", "signed");
                request.AddParameter("webhooks[0][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookSigned");
                request.AddParameter("webhooks[1][state]", "rejected");
                request.AddParameter("webhooks[1][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookRejected");
                request.AddParameter("webhooks[2][state]", "expired");
                request.AddParameter("webhooks[2][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookExpired");
                request.AlwaysMultipartFormData = true;
                request.AddFileBytes("file", bytes, anno.filename, anno.mimetype);
                IRestResponse response = client.Execute(request);
                if (response.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    BE.art_idokument iDokumentUpdate = new BE.art_idokument
                    {
                        Id = dokument.Id,
                        art_id = JsonConvert.DeserializeObject<UploadDokumentResponseClass>(response.Content).ContractId,
                        art_idokumentid = dokument.Id,
                        statuscode = new OptionSetValue(BE.art_idokument.Attr.statuscode.Options.A_Odeslany_k_podpisu)
                    };
                    _base.Trace = true;
                    _base.Debug(iDokumentUpdate, "iDokumentUpdate");


                    iDokumentUpdate.Update(_base.Service);
                    return response.Content;
                }
                return response.Content;
            }
            catch (Exception e)
            {
                _base.Error(e, "Art.IDocuments.Logic.AnnotationLogic.Upload");
                return e.Message;
            }
        }

// Upload From Template


        public string UploadTemplate(EntityReference dokumentReference)
        {
            try
            {
                BE.art_idokument dokument = _base.Service.Retrieve(BE.art_idokument.EntityLogicalName, dokumentReference.Id,
                    new ColumnSet(BE.art_idokument.Attr.art_customerid.LogicalName, BE.art_idokument.Attr.art_name.LogicalName, BE.art_idokument.Attr.art_sablonaid.LogicalName)).ToEntity<BE.art_idokument>();
                BE.art_idokumentsablona sablona = _base.Service.Retrieve(dokument.art_sablonaid.LogicalName, dokument.art_sablonaid.Id,
                    new ColumnSet(BE.art_idokumentsablona.Attr.art_emailautor.LogicalName, BE.art_idokumentsablona.Attr.art_mistopodpisu.LogicalName, BE.art_idokumentsablona.Attr.art_spolecnost.LogicalName, BE.art_idokumentsablona.Attr.art_stranapospisu.LogicalName)).ToEntity<BE.art_idokumentsablona>();
                BE.contact contact = _base.Service.Retrieve(BE.contact.EntityLogicalName, dokument.art_customerid.Id,
                    new ColumnSet(BE.contact.Attr.firstname.LogicalName, BE.contact.Attr.lastname.LogicalName, BE.contact.Attr.emailaddress1.LogicalName, BE.contact.Attr.mobilephone.LogicalName, BE.contact.Attr.address1_line1.LogicalName, BE.contact.Attr.description.LogicalName)).ToEntity<BE.contact>();
                QueryExpression queryAnno = new QueryExpression
                {
                    EntityName = BE.annotation.EntityLogicalName,
                    NoLock = true,
                    TopCount = 1,
                    ColumnSet = new ColumnSet(BE.annotation.Attr.filename.LogicalName, BE.annotation.Attr.mimetype.LogicalName, BE.annotation.Attr.documentbody.LogicalName),
                    Criteria = new FilterExpression(LogicalOperator.And)
                    {
                        Conditions =
                        {
                            new ConditionExpression(BE.annotation.Attr.objectid.LogicalName,ConditionOperator.Equal,dokument.Id)
                        }
                    }
                };
                List<BE.annotation> annotations = _base.Service.RetrieveMultiple<BE.annotation>(queryAnno);
                if (annotations.Count == 0) {
                    var client1 = new RestClient("https://api.signi.com/api/v1/contract/sign/template")
                    {
                        Timeout = -1
                    };
                    //client.UseNewtonsoftJson();
                    var request1 = new RestRequest(Method.POST);
                    //request.UseNewtonsoftJson();
                    request1.AddHeader("x-api-key", "71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f");
                    request1.AddHeader("Content-Type", "multipart/form-data");
                    request1.AddParameter("email_author", sablona.art_emailautor);
                    request1.AddParameter("email_signer", contact.emailaddress1);
                    request1.AddParameter("phone_signer", contact.mobilephone);
                    request1.AddParameter("firstname_signer", contact.firstname);
                    request1.AddParameter("lastname_signer", contact.lastname);
                    request1.AddParameter("proposer_sign", "true");
                    request1.AddParameter("negotiator_sign", "true");
                    request1.AddParameter("contract_name", dokument.art_name);
                    request1.AddParameter("contract_number", dokument.art_cislodokumentu);
                    request1.AddParameter("sign_date", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
                    request1.AddParameter("sign_place", sablona.art_mistopodpisu);
                    request1.AddParameter("last_document", "true");
                    request1.AddParameter("person_type", "legal");
                    //request.AddParameter("date_of_birth", "1970-04-16");
                    //request.AddParameter("street", "5. května 67");
                    //request.AddParameter("city", "Libčice nad Vltavou");
                    //request.AddParameter("zip_code", "25266");
                    request1.AddParameter("company_name", sablona.art_spolecnost);
                    //request.AddParameter("ic", "28524322");
                    //request.AddParameter("dic", "CZ28524322");
                    //request.AddParameter("sign_proposer", "{\"position\": {\"x\": 15,\"y\": 84,\"page\": 0}}");
                    //request.AddParameter("sign_negotiator", "{\"position\": {\"x\": 78,\"y\": 84,\"page\": 0}}");
                    //request.AddParameter("sign_proposer[position][x]", 8);
                    //request.AddParameter("sign_proposer[position][y]", 84);
                    //request.AddParameter("sign_proposer[position][page]", sablona.art_stranapospisu - 1);
                    //request.AddParameter("sign_negotiator[position][x]", 64);
                    //request.AddParameter("sign_negotiator[position][y]", 84);
                    //request.AddParameter("sign_negotiator[position][page]", sablona.art_stranapospisu - 1);
                    request1.AddParameter("webhooks[0][state]", "signed");
                    request1.AddParameter("webhooks[0][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookSigned");
                    request1.AddParameter("webhooks[1][state]", "rejected");
                    request1.AddParameter("webhooks[1][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookRejected");
                    request1.AddParameter("webhooks[2][state]", "expired");
                    request1.AddParameter("webhooks[2][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookExpired");
                    request1.AddParameter("template_id", 170);
                    request1.AddParameter("parameters", JsonConvert.SerializeObject( new[] { new { id = 411, value = contact.description } }));
                    //request1.AddParameter("parameters[0][id]", 411);
                    //request1.AddParameter("parameters[0][value]", contact.description);
                    IRestResponse response1 = client1.Execute(request1);
                    if (response1.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        BE.art_idokument iDokumentUpdate = new BE.art_idokument
                        {
                            Id = dokument.Id,
                            art_id = JsonConvert.DeserializeObject<UploadDokumentResponseClass>(response1.Content).ContractId,
                            art_idokumentid = dokument.Id,
                            statuscode = new OptionSetValue(BE.art_idokument.Attr.statuscode.Options.A_Odeslany_k_podpisu)
                        };
                        _base.Trace = true;
                        _base.Debug(iDokumentUpdate, "iDokumentUpdate");


                        iDokumentUpdate.Update(_base.Service);
                        return response1.Content;
                    }
                    return "Žádné přílohy";
                }
                
                BE.annotation anno = annotations[0];
                byte[] bytes = Convert.FromBase64String(anno.documentbody);
                //if (anno.filename.Contains("html"))
                //{
                //    byte[] data = Convert.FromBase64String(anno.documentbody);
                //    string decodedString = Encoding.UTF8.GetString(data);
                //    string newBodyText = decodedString.Replace("{data_z_dynamics1}", contact.description).Replace("{data_z_dynamics2}", contact.address1_line1);
                //    bytes = Encoding.UTF8.GetBytes(newBodyText);
                //}

                // Dokument stažený z Dynamics 365 DB
                var client = new RestClient("https://api.signi.com/api/v1/contract/sign/provided")
                {
                    Timeout = -1
                };
                //client.UseNewtonsoftJson();
                var request = new RestRequest(Method.POST);
                //request.UseNewtonsoftJson();
                request.AddHeader("x-api-key", "71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f");
                request.AddHeader("Content-Type", "multipart/form-data");
                request.AddParameter("email_author", sablona.art_emailautor);
                request.AddParameter("email_signer", contact.emailaddress1);
                request.AddParameter("phone_signer", contact.mobilephone);
                request.AddParameter("firstname_signer", contact.firstname);
                request.AddParameter("lastname_signer", contact.lastname);
                request.AddParameter("proposer_sign", "true");
                request.AddParameter("negotiator_sign", "true");
                request.AddParameter("contract_name", dokument.art_name);
                request.AddParameter("contract_number", dokument.art_cislodokumentu);
                request.AddParameter("sign_date", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
                request.AddParameter("sign_place", sablona.art_mistopodpisu);
                request.AddParameter("last_document", "true");
                request.AddParameter("person_type", "legal");
                //request.AddParameter("date_of_birth", "1970-04-16");
                //request.AddParameter("street", "5. května 67");
                //request.AddParameter("city", "Libčice nad Vltavou");
                //request.AddParameter("zip_code", "25266");
                request.AddParameter("company_name", sablona.art_spolecnost);
                //request.AddParameter("ic", "28524322");
                //request.AddParameter("dic", "CZ28524322");
                //request.AddParameter("sign_proposer", "{\"position\": {\"x\": 15,\"y\": 84,\"page\": 0}}");
                //request.AddParameter("sign_negotiator", "{\"position\": {\"x\": 78,\"y\": 84,\"page\": 0}}");
                request.AddParameter("sign_proposer[position][x]", 8);
                request.AddParameter("sign_proposer[position][y]", 84);
                request.AddParameter("sign_proposer[position][page]", sablona.art_stranapospisu - 1);
                request.AddParameter("sign_negotiator[position][x]", 64);
                request.AddParameter("sign_negotiator[position][y]", 84);
                request.AddParameter("sign_negotiator[position][page]", sablona.art_stranapospisu - 1);
                request.AddParameter("webhooks[0][state]", "signed");
                request.AddParameter("webhooks[0][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookSigned");
                request.AddParameter("webhooks[1][state]", "rejected");
                request.AddParameter("webhooks[1][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookRejected");
                request.AddParameter("webhooks[2][state]", "expired");
                request.AddParameter("webhooks[2][url]", "https://artidocumentswebapi.azurewebsites.net/IDocument/WebHookExpired");
                request.AlwaysMultipartFormData = true;
                request.AddFileBytes("file", bytes, anno.filename, anno.mimetype);
                IRestResponse response = client.Execute(request);
                if (response.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    BE.art_idokument iDokumentUpdate = new BE.art_idokument
                    {
                        Id = dokument.Id,
                        art_id = JsonConvert.DeserializeObject<UploadDokumentResponseClass>(response.Content).ContractId,
                        art_idokumentid = dokument.Id,
                        statuscode = new OptionSetValue(BE.art_idokument.Attr.statuscode.Options.A_Odeslany_k_podpisu)
                    };
                    _base.Trace = true;
                    _base.Debug(iDokumentUpdate, "iDokumentUpdate");


                    iDokumentUpdate.Update(_base.Service);
                    return response.Content;
                }
                return response.Content;
            }
            catch (Exception e)
            {
                _base.Error(e, "Art.IDocuments.Logic.AnnotationLogic.Upload");
                return e.Message;
            }
        }

// Download Document

        public void DownloadTest()
        {
            BE.annotation anno = (BE.annotation)_base.Service.Retrieve(BE.annotation.EntityLogicalName, new Guid("54DC0A3F-75A5-EA11-A812-000D3AB7AF7A"), new ColumnSet(true));
            RestClient client = new RestClient("https://api.signi.com/api/v1/contract/2842/download");
            client.AddDefaultHeader("x-api-key", "71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f");
            client.AddDefaultHeader("Content-Type", "application/json");

            IRestRequest request = new RestRequest
            {
                Method = Method.GET
            };
            IRestResponse response = client.Get(request);
            string fileBase64 = Convert.ToBase64String(response.RawBytes); //fileBase64 - serializovaný soubr, který je možné uložit do DB
        }

        public string Download(EntityReference dokumentReference)
        {
            try
            {
                string output = "OK";

                BE.art_idokument dokument = _base.Service.Retrieve(BE.art_idokument.EntityLogicalName, dokumentReference.Id,
    new ColumnSet(BE.art_idokument.Attr.art_customerid.LogicalName, BE.art_idokument.Attr.art_name.LogicalName, BE.art_idokument.Attr.art_sablonaid.LogicalName, BE.art_idokument.Attr.art_id.LogicalName)).ToEntity<BE.art_idokument>();

                QueryExpression queryAnno = new QueryExpression
                {
                    EntityName = BE.annotation.EntityLogicalName,
                    NoLock = true,
                    TopCount = 1,
                    ColumnSet = new ColumnSet(BE.annotation.Attr.filename.LogicalName),
                    Criteria = new FilterExpression(LogicalOperator.And)
                    {
                        Conditions =
                        {
                            new ConditionExpression(BE.annotation.Attr.objectid.LogicalName,ConditionOperator.Equal,dokument.Id)
                        }
                    }
                };
                List<BE.annotation> annotations = _base.Service.RetrieveMultiple<BE.annotation>(queryAnno);
                if (annotations.Count == 0) return "Žádné přílohy";
                BE.annotation anno = annotations[0];


                RestClient client = new RestClient($"https://api.signi.com/api/v1/contract/{dokument.art_id}/download");
                client.AddDefaultHeader("x-api-key", "71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f");
                client.AddDefaultHeader("Content-Type", "application/json");

                IRestRequest request = new RestRequest
                {
                    Method = Method.GET
                };
                IRestResponse response = client.Get(request);
                string fileBase64 = Convert.ToBase64String(response.RawBytes);
                BE.annotation annotation = new BE.annotation
                {
                    objectid = dokumentReference,
                    documentbody = fileBase64,
                    subject = $"Podepsaný dokument: {dokument.art_name}",
                    filename = $"{anno.filename}_podpis.pdf"
                };
                annotation.Create(_base.Service);
                return output;
            }
            catch (Exception e)
            {
                _base.Error(e, "Art.IDocuments.Logic.AnnotationLogic.Download");
                return e.Message;
            }
        }

    }
}


Code example in VBA 

Visual Basic for Application is a development language used in the desktop versions of Microsoft Office . It is no longer supported in the Office 365 cloud environment.

  • On the Signi production environment, the workspace is "Demo API" and has API key =  “71c4123d242bdd38047bee838d17e3367dc3ea6748d0975217ce501e834a224c83cab8afd35c9b0e6ade806b7987fae80f97f5c8253cfbb9089cf21f”, when making your calls, replace this API key with your workspace's API key, which you get by subscribing to the "API Integration" and API Key Generation services.

  • You need the code to run Micrisoft Excel for Desktop on MS Windows. VBA macros do not work on MS 356 cloud environment, and the object for HTTP requests is not accessible in Microsoft Execl for Mac.


Sub FillTemplateAndSend()

  Dim URL As String
  Dim JSONString As String
  Dim RowString As String
  Dim objHTTP As New WinHttpRequest
  Dim ConfProposerEmail As String
  Dim ConfAPIKey As String
  Dim ConfMapping As String
  Dim ConfURL As String
  Dim i As Integer
  Dim ContractFrom As Integer
  Dim ContractTo As Integer
  Dim Contracts As Range
  Dim SigniID As String
  Dim ResponseText As String
  Dim TemplateNo As Integer
  Dim TemplateRow As Integer
  
  'Načtení parametrů konfigurace
  
  ConfURL = "https://api.signi.com/api/v1/contract/?type=template"
  ConfAPIKey = Worksheets("Config").Range("C6").Value
  ContractFrom = 5 'první řádek na kterém jsou data
  ContractTo = Worksheets("Data").UsedRange.Rows.Count  'poslední řádek na kterém jsou data
 
  objHTTP.Open "POST", ConfURL, False
  objHTTP.SetRequestHeader "x-api-key", ConfAPIKey
  objHTTP.SetRequestHeader "Content-Type", "application/json"

  'procházení řádků , posílání do Signi a aktualizace řádků
  
  For i = ContractFrom To ContractTo
    If UCase(Worksheets("Data").Range("A" & i).Value) = "ODESLAT" Then
        TemplateNo = Worksheets("Data").Range("B" & i).Value
        If IsNumeric(TemplateNo) Then
        RowString = Worksheets("Config").Range("C" & (TemplateNo + 10)).Value
        RowString = Replace(RowString, "#proposeremail#", Worksheets("Config").Range("C7").Value)
        RowString = Replace(RowString, "#state#", Worksheets("Config").Range("C8").Value)
        RowString = Replace(RowString, "#locale#", Worksheets("Config").Range("C9").Value)
    
    
        If TemplateNo = "1" Then
            RowString = Replace(RowString, "#contract_name#", Worksheets("Data").Range("E" & i).Value)
            RowString = Replace(RowString, "#number#", Worksheets("Data").Range("F" & i).Value)
            RowString = Replace(RowString, "#firstname#", Worksheets("Data").Range("G" & i).Value)
            RowString = Replace(RowString, "#lastname#", Worksheets("Data").Range("H" & i).Value)
            RowString = Replace(RowString, "#email#", Worksheets("Data").Range("I" & i).Value)
            RowString = Replace(RowString, "#phone#", Worksheets("Data").Range("J" & i).Value)
            RowString = Replace(RowString, "#112#", Worksheets("Data").Range("K" & i).Value)
            RowString = Replace(RowString, "#122#", Worksheets("Data").Range("L" & i).Value)
            RowString = Replace(RowString, "#131#", Worksheets("Data").Range("M" & i).Value)
            RowString = Replace(RowString, "#411#", Worksheets("Data").Range("N" & i).Value)
            RowString = Replace(RowString, "#421#", Worksheets("Data").Range("O" & i).Value)
            RowString = Replace(RowString, "#431#", Worksheets("Data").Range("P" & i).Value)
        End If
                
        objHTTP.Send RowString
        ResponseText = objHTTP.ResponseText
        ResponseText = Replace(ResponseText, "{""contract_id"":", "")
        If InStr(ResponseText, """attachments""") >= 2 Then
          SigniID = Left(ResponseText, InStr(ResponseText, """attachments""") - 2)
        Else
          SigniID = ResponseText 'pokud chybí text "attachements", předpokládá se, že došlo k chybě
        End If
        Worksheets("Data").Range("D" & i) = RowString ' JSON použitý pro volání
        Worksheets("Data").Range("C" & i) = SigniID
        Worksheets("Data").Range("A" & i).Value = "Odesláno"
     End If
     End If
  Next i
Dim Z As String

End Sub



Sub ReadStatus()
  Dim ConfURL As String
  Dim ConfAPIKey As String
  Dim URL As String
  Dim SigniID As String
  Dim ResponseText As String
  Dim i As Integer
  Dim ContractFrom As Integer
  Dim ContractTo As Integer
  Dim objHTTP As New WinHttpRequest
  
  
  
  'Načtení parametrů konfigurace
  
  ConfAPIKey = Worksheets("Config").Range("C6").Value
  ConfURL = "https://api.signi.com/api/v1/contract/"
  ContractFrom = 5
  ContractTo = Worksheets("Data").UsedRange.Rows.Count
 
  'procházení řádků , posílání do Signi a aktualizace řádků
  
  For i = ContractFrom To ContractTo
    SigniID = Worksheets("Data").Range("B" & i).Value 'Načtení SigniID ze sloupce D
    If IsNumeric(SigniID) And Not (IsEmpty(SigniID)) Then 'když je hodnota numerická a neprázdná tj.j. je v ní pravděpodobně smysluplné ContractID
        URL = ConfURL & SigniID
        
        objHTTP.Open "GET", URL, False
        objHTTP.SetRequestHeader "x-api-key", ConfAPIKey
        objHTTP.SetRequestHeader "Content-Type", "application/json"

        
        objHTTP.Send
        ResponseText = objHTTP.ResponseText
        If InStr(ResponseText, """pending""") > 0 Then
            Worksheets("Data").Range("A" & i).Value = "Rozesláno"
        ElseIf InStr(ResponseText, """completed""") > 0 Then
            Worksheets("Data").Range("A" & i).Value = "Podepsáno"
        ElseIf InStr(ResponseText, """expired""") > 0 Then
            Worksheets("Data").Range("A" & i).Value = "Uplynula doba"
        ElseIf InStr(ResponseText, """refused""") > 0 Then
            Worksheets("Data").Range("A" & i).Value = "Odmítnuto"
        End If
        
     End If
  Next i



End Sub


Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article