The Best Rated EmaiI Signature Portal

Xink Developer API

Xink provides REST API for external clients.
All traffic between a client application and Xink service (Xink Developer API) is transported by encrypted HTTP requests and responses.

Authentication/Authorization

We use OAuth2 to control access to Xink developer API; external clients should use ClientCredentialsGrant in particular. The client should request the access token from the Xink authorization server, then use the token in all subsequent requests to the API.

In Xink admin you create an API user. Navigate to ‘preferences-> admins’ and add an API user. Give the user proper permissions and a good password. The ‘user’ referred to in this documentation is an API user.

Authorization server URI
Authorization endpoint
/OAuth/Authorize
Token endpoint
/OAuth/Token

Here is a C# sample

            string accessToken = null;
            DateTime accessTokenExpiryTime;

            var authorizationServerUri = new Uri("https://auth.xink.io");

            var client = new HttpClient();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
                "Basic", 
                Convert.ToBase64String(
                    System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(
                        string.Join(":",
                        "some-user-id@SRV",
                        "theverysecretpassword"))));

            KeyValuePair<string, string>[] formData = new KeyValuePair<string, string>[]
            {
                new KeyValuePair<string,string>("grant_type","client_credentials"),
                new KeyValuePair<string, string>("scope","employeeread employeesignaturesread"),
            };

            var content = new FormUrlEncodedContent(formData);
            var response = client.PostAsync(new Uri(authorizationServerUri, "/OAuth/Token"), content).Result;

            if (response.StatusCode == HttpStatusCode.OK)
            {
                var rdata = response.Content.ReadAsStringAsync().Result;
                IDictionary<string, string> data = JsonConvert.DeserializeObject<Dictionary<string, string>>(rdata) as IDictionary<string, string>;

                accessToken = data["access_token"];
                accessTokenExpiryTime = DateTime.UtcNow.AddSeconds(int.Parse(data["expires_in"]));
            }
            else if (response.StatusCode == HttpStatusCode.BadRequest)
            {
                var rdata = response.Content.ReadAsStringAsync().Result;
                IDictionary<string, string> data = JsonConvert.DeserializeObject<Dictionary<string, string>>(rdata) as IDictionary<string, string>;
            }

            if (string.IsNullOrEmpty(accessToken))
            {
                Console.WriteLine("Couldn't obtain token.");
                return;
            }

Please note scope names “employeeread” and “employeesignaturesread”, as these are required to get employee list and signatures.
Each operation may require some scope.

By default, the token is valid for 2 hours from the time of the authorization request. At a later point, this value might be changed to 10-15 minutes.

Finding API server

After obtaining the access token client should call the discovery service and get the API server DNS name, it is different for accounts in different data centers. Discovery service URL is https://auth.xink.io/discovery, this can be hardcoded.

The service returns a simple JSON object containing the APIRoot parameter.

            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);

            var dcConfig = client.GetStringAsync(
                new Uri(
                    authorizationServerUri,
                    "/discovery"
                    )
                ).Result;

            IDictionary<string, string> dcConfigData = JsonConvert.DeserializeObject<Dictionary<string, string>>(dcConfig) as IDictionary<string, string>;

            var resourceServerUri = new Uri(dcConfigData["APIRoot"]);


The last variable here, resourceServerUri, contains the API root reference.

Employees

List employees

We use OAuth2 to control access to Xink APIs; external clients should use ClientCredentialsGrant in particular. The client should request the access token from the Xink authorization server, then use the token in all subsequent requests to the Xink API.

Route

api/1.0/employee/list

Authorization scope

employeeread

Parameters

offset: integer, default is 0. Position 0
limit: integer, default is 500. Position 1

Response format (sample)

{
“Offset”: 0,
“Limit”: 3,
“Items”: [
{
“Email”: “johndoe@example.com”,
“FirstName”: “John”,
“LastName”: “Doe”,
“DisplayName”: “John Doe”
},


]


Xink API URL for fetching the first three employees would be api/1.0/employee/list/0/3


The response contains Offset and Limit parameter values used in the request (or defaults if not parameters are supplied). In the array of Items, each represents one employee.

Employee list items:

  • Email — employee email is a system-wide unique value used to refer employee in any calls. Cannot be empty.
  • FirstName — corresponds to Xink First name field.
  • LastName — corresponds to Xink Last name field.
  • DisplayName — corresponds to the Xink Display Name field. Cannot be empty.
Invite employee
MethodPOST
Route

api/1.0/employee/invite

Authorization scope

employeeread

Parameters

none

Response format(sample)

none

Request body (sample)

{

    "Email": “user1@example.com”

}
List employee profile
MethodGET
Route

api/1.0/employee/listprofile/{offset:int=0}/{limit:int=200}

Authorization scope

employeefieldsread

Parameters

offset: integer, default is 0. Position 0

limit: integer, default is 500. Position 1 

Response format(sample)

{

    "Limit": 200,

    "Offset": 0,

    "Items": [

        {

             "Email": “user1@example.com",

             "FirstName": "Test",

            "LastName": "Test",

             "DisplayName": "Test Test",

             "Fields": [

                {

                     "Code": "FirstName",

                     "DisplayName": "First Name",

                     "FieldValue": "Test",

                     "IsImage": false

                },

      ]

}
Request body (sample)

none


Get employee signatures
Route

api/1.0/employee/{email}/signatures

Authorization scope

employeesignaturesread

Parameters

email: email address of the employee

Response format (sample)

{
“Clean”: true,
“SetDefault”: true,
“SetReply”: true,
“Signatures”: [
{
“Name”: “Some Name”,
“HTML”: “<p>Sincerely,<br/>John Doe</p>”,
“Text”: “Sincerely,\r\nJohn Doe”,
“DefaultNew”: true,
“DefaultReply”: true
},

],
“Images”: [
{
“Name”: “images-Get-i62-f.jpg”,
“URL”: “https://app.xink.io/Images/Get/i62/i.jpg”
},

]
}


URL for fetching John Doe’s signature would be api/1.0/employee/johndoe@example.com/signatures

The response contains the Clean flag which represents the value of “Delete all existing email signatures in Outlook” preference; SetDefault and SetReply flags indicating if the client application is supposed to assign new/reply signatures in Outlook and actual array of Signatures and Images.


Signature list items:

  • Name — the name of the signature in Xink, the same value is displayed in the web application, in the signature list. Cannot be empty.
  • HTML — this is the actual HTML signature with all substitutions performed, ready for use by a specific employee.
  • Text — plain text version of the signature, also ready for use.
  • DefaultNew — a boolean flag indicating that the signature is configured to be the default for new messages.
  • DefaultReply — a boolean flag indicating that the signature is configured to be the default for forward/reply messages.


Images list items:

  • Name — file name for the image
  • URL — direct link to fetch the image.


The signature is supposed to be downloaded directly into the “Signatures” folder of the Outlook user profile. Each signature must be saved into a file named exactly as field Name value with the .htm extension added.

Get employee fields
Route

api/1.0/employee/{email}/fields

Authorization scope

employeefieldsread

Parameters

email: email address of the employee

Response format (sample)

{
“Fields”: [
{
“Code”: “Mobile”,
“DisplayName”: “<p>Sincerely,<br/>John Doe</p>”,
“FieldValue”: “Sincerely,\r\nJohn Doe”
},

]
}


URL for fetching John Doe’s fields would be api/1.0/employee/johndoe@example.com/fields

The response contains an array of Fields.


Field list items:

  • Code — internal name of Xink field; used by Xink to refer field data in signatures, like ((Mobile)). Mobile is the code.
  • DisplayName — human-readable name (or description) of the field.
  • FieldValue — the actual value of the field for the corresponding user in a moment when API calls made.
List fields
Method

GET

Route

api/1.0/fields/list

Authorization scope

employeefieldsread

Parameters

none

Response format (sample)

{

    "Fields": [

        {

             "Code": "FirstName",

             "DisplayName": "First Name",

             "FieldType": 1,

             "DirectoryMapping": "givenName"

        },

        {

             "Code": "LastName",

             "DisplayName": "Last Name",

             "FieldType": 1,

        }

    ]

}
Upload employees
Method

POST

Route

api/1.0/employee/upload

Authorization scope

employeectrl

Parameters

none

Request body (sample)

{
“Items”: [
{
“Email”:”user1@testapi.com”,
“FirstName”:”John”,
“LastName”:”Doe”,
“DisplayName”:”John Doe”,
“Fields”: [
{
“Code”:”City”,
“FieldValue”:”New York”
},
{
“Code”:”Country”,
“FieldValue”:”USA”
},
]
},
{
“Email”:”user2@testapi.com”,
“FirstName”:”Peter”,
“LastName”:”Johnson”,
“DisplayName”:””,
“Fields”: [
{
“Code”:”Department”,
“FieldValue”:”Sales”
},
{
“Code”:”Facebook”,
“FieldValue”:””
}
]
}
]
}

Response format (sample)

{
“Items”: [
“user1@testapi.com: OK”,
“user2@testapi.com: OK”
]
}


Upload list items:

  • Email — employee email. A mandatory field, a unique employee identifier in the system-wide.
  • FirstName — corresponds to Xink First name field. A mandatory field for new employees. It can be left blank for already existed employees. It won’t change in this case.
  • LastName — corresponds to Xink Last name field. A mandatory field for new employees. It can be left blank for already existed employees. It won’t change in this case.
  • DisplayName — corresponds to the Xink Display Name field. Can be empty. In this case “FirstName LastName” will be applied.
  • Fields — a list of the employee custom fields. Only the fields in the list are gonna change. The field FieldValue can be empty. The fields should be created in Xink. If the request contains the fields, which can’t be found in Xink, the employee won’t be added. The server answer contains the message with the successful employee update or error description.
Delete employees
Method

POST

Route

api/1.0/employee/delete

Authorization scope

employeectrl

Parameters

none

Request body (sample)

{
“Items”: [
{
“Email”:”user1@testapi.com”
},
{
“Email”:”user2@testapi.com”
}
]
}


Response format (sample)

none


Delete list items:

  • Email — employee email. A mandatory field, a unique employee identifier in the system-wide.

Images

Images

The signature may contain images, like the company logo, employee avatar or whatever else. Xink stores those images and performs several actions to prepare Outlook application to use them properly.

Field Name provides the exact file name for the corresponding image. Images supposed to be saved in the same directory as signatures. It is important; signature HTML refers to images just by file name.

Xink server is responsible for making image names unique. If in any case image names are repeated, it is guaranteed that these are references to the same image.

There is no dedicated authorization scope for image access. It is enough to provide a token generated for a valid client account.

Example

            var body = client.GetStringAsync(
                new Uri(
                    resourceServerUri,
                    "/api/1.0/employee/johndoe@example.tld/signatures"
                    )
                ).Result;

Did you find it helpful? Yes No

Send feedback
Sorry we couldn't be helpful. Help us improve this article with your feedback.