Xink API Reference
Version: 1.3
Date: Jan 15, 2025
Table of Contents
Overview
Xink provides REST API for external clients. All traffic between a client application and Xink service is transported by encrypted HTTP requests and responses.
API service URI:
https://e-{dc}.xink.io/
API service URI for US DC:https://e.xink.io/
Authentication/Authorization
We use OAuth2 to control access to Xink APIs, external clients should use ClientCredentialsGrant in particular. Client should request access token from Xink authorization server, then use the token in all subsequent requests to the API.
In Xink admin portal you need to 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:
https://auth.xink.io
Authorization endpoint:/OAuth/Authorize
Token endpoint:/OAuth/Token
// C# example
var authorizationServerUri = new Uri("https://auth.xink.io");
var authorizationServer = new AuthorizationServerDescription
{
AuthorizationEndpoint = new Uri(authorizationServerUri, "/OAuth/Authorize"),
TokenEndpoint = new Uri(authorizationServerUri, "/OAuth/Token")
};
_webServerClient = new WebServerClient(authorizationServer, "some-id-here@SRV", "secretpassword");
var state = _webServerClient.GetClientAccessToken(new[] { "employeeread", "employeesignaturesread" });
_accessToken = state.AccessToken;
Please note scope names employeeread
and employeesignaturesread
, these are required to get employee list and signatures. Each operation may require some scope.
By default token is valid for 2 hours since authorization request. On later stages, this value might be changed to 10-15 minutes.
Summary of All Available API Controllers
Account
[HttpGet, Route("api/1.0/account/info")]
Employee
[HttpGet, Route("api/1.0/employee/list/{offset:int=0}/{limit:int=500}")]
[HttpGet, Route("api/1.0/employee/{email}/fields")]
[HttpGet, Route("api/1.0/employee/{email}/signatures")]
[HttpPost, Route("api/1.0/employee/upload")]
[HttpPost, Route("api/1.0/employee/delete")]
Image
[HttpPost, Route("api/1.0/image")]
[HttpGet, Route("api/1.0/image/list/{offset:int=0}/{limit:int=500}")]
Signature
[HttpGet, Route("api/1.0/signature/list/{offset:int=0}/{limit:int=500}")]
[HttpPost, Route("api/1.0/signature/")]
[HttpPost, Route("api/1.0/signature/{id}/update")]
[HttpDelete, Route("api/1.0/signature/{id}")]
[HttpPost, Route("api/1.0/signature/{id}/delete")]
Signature Import
[HttpPost, Route("api/1.0/signatureimport/{id}/image")]
[HttpPost, Route("api/1.0/signatureimport/{id}")]
Rerouting
[HttpGet, Route("api/1.0/rerouting/status")]
[HttpPost, Route("api/1.0/rerouting/clearmap")]
[HttpPost, Route("api/1.0/rerouting/replacemap")]
Managed Accounts
[HttpGet, Route("api/1.0/managedAccounts/list")]
Shared Mailboxes
[HttpPost, Route("api/1.0/employees/{email}/sharesSignatureWith/{emailSharedWith}")]
[HttpDelete, Route("api/1.0/employees/{email}/sharesSignatureWith/{emailSharedWith}")]
[HttpGet, Route("api/1.0/employees/{email}/shared")]
Examples of API Controller's Request-Response
Scopes
Account
[HttpGet, Route("api/1.0/account/info")]
Scope: employeeread
{
"CompanyName": "Some Company",
"LicensedEdition": "Xink Campaign",
"LicensedCount": 6,
"CreatedDate": "2013-02-07T07:37:52.78",
"RenewalDate": null,
"InvoiceEmail": "[email protected]",
"TotalEmployees": 530,
"Signatures": 32,
"DefaultSignature": null,
"ReplySignature": null,
"RunningCampaigns": [
{
"Name": "disclaimer2",
"ContentText": null,
"ContentHTML": "disclaimer2",
"Active": true,
"TrackClicks": true,
"Weight": 2,
"Notes": null,
"EffectiveActive": true,
"SignaturesCount": 0,
"ClickCount": 0,
"ViewCount": 8
},
{
"Name": "Subscribe",
"ContentText": null,
"ContentHTML": "",
"Active": true,
"TrackClicks": true,
"Weight": 1,
"Notes": null,
"EffectiveActive": true,
"SignaturesCount": 1,
"ClickCount": 11,
"ViewCount": 15
}
],
"UpcomingCampaigns": [],
"TopCampaigns": [],
"DisabledCampaigns": [
{
"Name": "__custom_tracking_link_01",
"ContentText": null,
"ContentHTML": null,
"Active": false,
"TrackClicks": true,
"Weight": 1,
"Notes": null,
"EffectiveActive": false,
"SignaturesCount": 1,
"ClickCount": 0,
"ViewCount": 53
},
{
"Name": "new campaign",
"ContentText": null,
"ContentHTML": null,
"Active": false,
"TrackClicks": true,
"Weight": 1,
"Notes": null,
"EffectiveActive": false,
"SignaturesCount": 0,
"ClickCount": 0,
"ViewCount": 0
}
],
"DateFrom": "2023-07-09T00:00:00+00:00"
}
Employee
[HttpGet, Route("api/1.0/employee/list/{offset:int=0}/{limit:int=500}")]
Example: /api/1.0/employee/list/0/3
Response contains Offset and Limit parameters values used in the request (or defaults if no parameters were supplied); and actual array of Items, each represents one employee.
Scope: employeeread
{
"Limit": 500,
"Offset": 0,
"SearchQuery": null,
"Items": [
{
"Email": "[email protected]",
"FirstName": "John",
"LastName": "Doe",
"DisplayName": "Jonny D"
},
{
"Email": "[email protected]",
"FirstName": "Maria",
"LastName": "Doe",
"DisplayName": "Maria D"
}
]
}
[HttpGet, Route("api/1.0/employee/{email}/fields")]
Scope: employeefieldsread
{
"Fields": [
{
"Code": "Country",
"DisplayName": "Country",
"FieldValue": null,
"IsImage": false
},
{
"Code": "DisplayName",
"DisplayName": "Display Name",
"FieldValue": "somename",
"IsImage": false
},
{
"Code": "LastName",
"DisplayName": "Last Name",
"FieldValue": "somename",
"IsImage": false
},
{
"Code": "Email",
"DisplayName": "Employee's Email",
"FieldValue": "[email protected]",
"IsImage": false
}
]
}
[HttpGet, Route("api/1.0/employee/{email}/signatures")]
Scope: employeesignaturesread
{
"Clean": false,
"SetDefault": true,
"SetReply": false,
"Signatures": [
{
"Name": "",
"HTML": null,
"Text": null,
"DefaultNew": false,
"DefaultReply": true
},
{
"Name": "(KM) 3-4-Sterne Offerte",
"HTML": "
[HttpPost, Route("api/1.0/employee/upload")]
Scope: employeectrl
Request:
{
"Items": [
{
"Email":"[email protected]",
"FirstName":"John",
"LastName":"Doe",
"DisplayName":"John Doe",
"Fields": [
{
"Code":"City",
"FieldValue":"New York"
},
{
"Code":"Country",
"FieldValue":"USA"
}
]
},
{
"Email":"[email protected]",
"FirstName":"Peter",
"LastName":"Johnson",
"DisplayName":"",
"Fields": [
{
"Code":"Department",
"FieldValue":"Sales"
},
{
"Code":"Facebook",
"FieldValue":""
}
]
}
]
}
Response:
{
"Items": [
"[email protected]: OK",
"[email protected]: OK"
]
}
[HttpPost, Route("api/1.0/employee/delete")]
Scope: employeectrl
Request:
{
"Items": [
{
"Email":"[email protected]"
},
{
"Email":"[email protected]"
}
]
}
Response: None
Image
Signature may contain images, like 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 exact file name for corresponding image. Images supposed to be saved in the same directory as signatures. It is important; signature HTML refers 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 valid client account.
[HttpPost, Route("api/1.0/image")]
Content-Type: multipart/form-data
Key: file
Value: someImg.png
Response:
{
"AccountUniqueName": "BT4",
"ImageUniqueName": "i",
"RelativeImageUrl": "https://i.xink.io/Images/Get/BT4/i.png",
"Name": "img21.png",
"DateCreated": "2023-10-10T09:18:18.21",
"MD5": "3A16278045564DAEIUB5A52B23C8B",
"SHA1": "A327FCE8098NIJN1E39D2683616DE71CBA4"
}
[HttpGet, Route("api/1.0/image/list/{offset:int=0}/{limit:int=500}")]
Scope: signaturectrl
{
"Limit": 500,
"Offset": 0,
"Items": [
{
"AccountUniqueName": "B4",
"ImageUniqueName": "i6",
"RelativeImageUrl": "https://i.xink.io/Images/Get/B4/i6.png",
"Name": "image001.png",
"DateCreated": "2014-06-18T11:59:38.843",
"MD5": "255F0174C3EOKN230283222FEE",
"SHA1": "89E5C303A9D90283NEED815735FF2C5239871"
},
{
"AccountUniqueName": "B3",
"ImageUniqueName": "i1",
"RelativeImageUrl": "https://i.xink.io/Images/Get/B3/i1.png",
"Name": "image002.png",
"DateCreated": "2014-06-18T12:19:18.76",
"MD5": "51BCBB0923NJEB223A2BA122E0",
"SHA1": "FC4907WOEINR0293712AF8BF8D9C727D15"
}
]
}
Signature
[HttpGet, Route("api/1.0/signature/list/{offset:int=0}/{limit:int=500}")]
Scope: signaturectrl
{
"Limit": 500,
"Offset": 0,
"Items": [
{
"SignatureID": "372236",
"Name": "eMailSignature",
"ContentText": "((FirstName)) ((LastName))\r\n((JobTitle))\r\n\r\n((Company))\r\n((Department))\r\nEmail: ((Email))\r\nPhone: ((DirectPhone))\r\n((WebSite))",
"ContentHTML": "
\r\n((FirstName)) ((LastName))
\r\n((JobTitle))\r\n\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n
\r\n",
"DefaultNew": false,
"DefaultReply": false,
"Available": false,
"Public": false,
"Notes": null
}
]
}
[HttpPost, Route("api/1.0/signature/")]
Name (string, required): The name of the signature.
ContentText (string, required): The text content of the signature.
ContentHTML (string, required): The HTML content of the signature.
Notes (string, optional): Optional notes or additional information about the signature.
Request:
{
"Name": "MySignature",
"ContentText": "Hello, this is my signature text.",
"ContentHTML": "Hello, this is my HTML signature.
",
"Notes": "Optional notes about the signature"
}
Response:
{
"SignatureID": "12345"
}
[HttpPost, Route("api/1.0/signature/{id}/update")]
Scope: signaturectrl
Request:
{
"Name": "MySignature-UPDATED",
"ContentText": "Hello, this is my signature text UPDATED.",
"ContentHTML": "Hello, this is my HTML signature UPDATED.
",
"Notes": "Optional notes about the signature UPDATED"
}
Response:
{
"SignatureID": "12345"
}
[HttpDelete, Route("api/1.0/signature/{id}")]
[HttpPost, Route("api/1.0/signature/{id}/delete")]
Rerouting
[HttpGet, Route("api/1.0/rerouting/status")]
{
"StatusCode": 0,
"Domains": [],
"IsSMTPCacheReady": true
}
[HttpPost, Route("api/1.0/rerouting/clearmap")]
[HttpPost, Route("api/1.0/rerouting/replacemap")]
Managed Accounts
[HttpGet, Route("/api/1.0/managedAccounts/list")]
Scope: managedaccountsread
{
"Items": [
{
"id": 26845,
"name": "admin1",
"email": "[email protected]",
"employees": 1,
"licenses": 0,
"version": "Brand",
"using": 0,
"note": "4",
"folders": [],
"createdDate": "2019-02-22T08:45:29.36",
"endDate": null
},
{
"id": 28760,
"name": "[email protected]",
"email": "[email protected]",
"employees": 1,
"licenses": 0,
"version": "Brand",
"using": 0,
"note": "111221",
"folders": [
"1"
],
"createdDate": "2019-04-24T15:22:24.157",
"endDate": "2019-05-08T00:00:00"
},
{
"id": 30598,
"name": "admin3",
"email": "[email protected]",
"employees": 1,
"licenses": 0,
"version": "Brand",
"using": 0,
"note": "2",
"folders": [
"1",
"2"
],
"createdDate": "2019-06-18T06:58:56.243",
"endDate": null
}
]
}
Shared Mailboxes
[HttpPost, Route("api/1.0/employees/{email}/sharesSignatureWith/{emailSharedWith}")]
Scope: employeectrl
Adds shared employee. The employee {emailSharedWith} can use the signatures of the employee {email}
[HttpDelete, Route("api/1.0/employees/{email}/sharesSignatureWith/{emailSharedWith}")]
Scope: employeectrl
Deletes shared employee.
[HttpGet, Route("api/1.0/employees/{email}/shared")]
Scope: employeectrl
Returns a list of shared employees whose signatures can be used by employee {email}
{
"Email": "[email protected]",
"SharedEmployees": [
{
"Email": "[email protected]",
"DisplayName": "Sam Doe"
}
]
}