A package containing sample code is available for download at https://api.counsellink.net/artifacts/client-examples.zip. This package contains a README.txt file which provides further details regarding accessing and using the API.
Code samples have been created to help developers with creating an HMAC digest that must be and is always passed in the authorization header of every CounselLink® EDI REST API call. These code samples, where applicable, can be found for the Java and C# programming languages. Once you have the code example for your preferred programming language implemented and executed in your local environment you can go over to the CounselLink API page to start expanding your application and implementing all the preferred API calls.
Jump to a topic to view samples:
Generate String to Sign -- Java Code Sample
The following code samples (Java and C#) shows you how to generate the string that must be signed, and the signature sent in the authorization header:
public String generateStringToSign(String verb, String contentType, String contentMD5, String iso8601Date, String resourceURL) {
StringBuilder stringToSign = new StringBuilder();
stringToSign.append(verb)
.append("\n")
.append(contentType)
.append("\n")
.append(contentMD5)
.append("\n")
.append(iso8601Date)
.append("\n")
.append(resourceURL)
.append("\n");
return stringToSign.toString();
}
where:
-
contentType and contentMD5 are needed only for a POST request
-
contentMD5 is the MD5 hash of the payload of a POST request.
Supported Content Types
The supported content types are application/json , application/vnd.cl.int.api.v1.0.0+json and multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\nabcde181845a4ca6b8fec737b3512345.
For a GET request, there is no need to append contentType and contentMD5. You do need to append new lines.
How to Generate the String to Sign
The following snippet shows how to generate the string to sign for a GET request.
public String generateStringToSign(String verb, String contentType, String contentMD5, String iso8601Date, String resourceURL) {
StringBuilder stringToSign = new StringBuilder();
stringToSign.append(verb)
.append("\n")
.append("\n")
.append("\n")
.append(iso8601Date)
.append("\n")
.append(resourceURL)
.append("\n");
return stringToSign.toString();
}
Jump to a sample for String to Sign (Java Code):
Generate HMAC Digest
The Java code snippet shows how to generate the signature of the string from the previous Generate String to Sign step.
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public String generateHmacDigest(String stringToSign, String secretKey) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKeySpec);
byte[] hmac = mac.doFinal(stringToSign.getBytes("UTF-8"));
String encodedHmac = Base64.getEncoder().encodeToString(hmac);
return encodedHmac;
}
}
Complete Example of a GET Request
Headers
GET /invoice/F678DCAD-35A3-43DE-A9B0-95F1F4AFEA74 HTTP/1.1
Host: localhost
x-ln-cl-int-api-date: 2017-07-12T13:00:00.000Z
Authorization: CL-INT-API qO5paii108tQ0GdqFT1USw==:zxwdBatKLfeESgaSeiqsDUJDLFlgGT96k2y+6eXtpf8=
Connection: Keep-Alive
HMAC Utility Class
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class HmacUtil {
public static String generateStringToSign(String verb, String contentType, String contentMD5, String iso8601Date, String resourceURL) {
StringBuilder stringToSign = new StringBuilder();
stringToSign.append(verb)
.append("\n")
.append(contentType)
.append("\n")
.append(contentMD5)
.append("\n")
.append(iso8601Date)
.append("\n")
.append(resourceURL)
.append("\n");
return stringToSign.toString();
}
public static String generateHmacDigest(String stringToSign, String secretKey) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKeySpec);
byte[] hmac = mac.doFinal(stringToSign.getBytes("UTF-8"));
String encodedHmac = Base64.getEncoder().encodeToString(hmac);
return encodedHmac;
}
}
HTTP GET Example
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
public class HttpGetExample {
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, ClientProtocolException, IOException {
String url = "http://localhost:8090/invoice/F678DCAD-35A3-43DE-A9B0-95F1F4AFEA74";
String accessKey = "access_key";
String secretKey = "secret_key";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
request.addHeader("x-ln-cl-int-api-date", "2017-07-12T13:00:00.000Z");
String stringToSign = HmacUtil.generateStringToSign(request.getMethod(), "", "", request.getFirstHeader("x-ln-cl-int-api-date").getValue(), request.getURI().getPath());
String hmacDigest = HmacUtil.generateHmacDigest(stringToSign, secretKey);
request.addHeader("Authorization", String.format("CL-INT-API %s:%s", accessKey, hmacDigest));
HttpResponse response = httpClient.execute(request);
System.out.println(response.getStatusLine().getStatusCode());
}
}
Complete Example of a POST Request
Headers
POST /matter HTTP/1.1
Content-Type: application/vnd.cl.int.api.v1.0.0+json
x-ln-cl-int-api-contentmd5 : abcde181845a4ca6b8fec737b3512345
x-ln-cl-int-api-date : 2017-07-12T13:00:00.000Z
Authorization: CL-INT-API qO5paii108tQ0GdqFT1USw==:zxwdBatKLfeESgaSeiqsDUJDLFlgGT96k2y+6eXtpf8=
HTTP POST Example
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import com.google.gson.Gson;
import com.lxnx.edi.restapi.v1.builders.MatterBuilder;
import com.lxnx.edi.restapi.v1.datatypes.MatterStatus;
import com.lxnx.edi.restapi.v1.dto.Matter;
public class HttpPostExample {
public static void main(String[] args) throws Exception {
String url = "http://localhost:8090/matter";
String accessKey = "access_key";
String secretKey = "secret_key";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost request = new HttpPost(url);
request.addHeader("x-ln-cl-int-api-date", "2017-07-12T13:00:00.000Z");
Matter matter = new MatterBuilder()
.withMatterNumber("TestMatterNumber")
.withTitle("Test Matter")
.withCurrencyCode("USD")
.withStatus(MatterStatus.ACTIVE)
.withContactOfficeName("LexisNexis")
.withMatterContact("user1")
.withInvoiceContact("user2")
.withTypeGuid("13eed3d8-17fb-447f-bbb2-9b6d9eb945aa")
.build();
request.addHeader("Content-Type", "application/vnd.cl.int.api.v1.0.0+json");
String md5 = DigestUtils.md5Hex(matter.toString());
request.addHeader("x-ln-cl-int-api-contentmd5", md5);
request.setEntity(new StringEntity(new Gson().toJson(matter)));
String stringToSign = HmacUtil.generateStringToSign(request.getMethod(), "application/vnd.cl.int.api.v1.0.0+json", md5, request.getFirstHeader("x-ln-cl-int-api-date").getValue(), request.getURI().getPath());
String hmacDigest = HmacUtil.generateHmacDigest(stringToSign, secretKey);
request.addHeader("Authorization", String.format("CL-INT-API %s:%s", accessKey, hmacDigest));
HttpResponse response = httpClient.execute(request);
System.out.println(response.getStatusLine().getStatusCode());
}
}
JavaComplete Example of a PUT UCDF Request
package com.lxnx.edi.restapi.security;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.HttpClientBuilder;
public class HttpUcdfPutExample {
public static void main(String[] args) throws Exception {
/*
This is the URL to update a UCDF field.
The format is /ucdf/{entityType}/{entityGuid}/{fieldType}/{fieldName}/{value}
In this example, entity type is MATTER, entity guid is 3A3FB1E6-1F82-4FCE-8E78-91CE16EBB6BF, the ucdf field type that we are updating is of type TEXT, the Inbound EDI name of the field we are trying to update is TestField1 and
ABCD-123 is the value we want to set on the ucdf field
*/
String url = "http://localhost:8090/ucdf/MATTER/3A3FB1E6-1F82-4FCE-8E78-91CE16EBB6BF/TEXT/TestField1/ABCD-123";
String accessKey = "USE YOUR ACCESS KEY";
String secretKey = "USE YOUR SECRET KEY";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPut request = new HttpPut(url);
request.addHeader("x-ln-cl-int-api-date", "2018-06-06T15:34:00.000Z");
request.addHeader("Content-Type", "application/vnd.cl.int.api.v1.0.0+json");
String stringToSign = HmacUtil.generateStringToSign(request.getMethod(), "application/vnd.cl.int.api.v1.0.0+json", null, request.getFirstHeader("x-ln-cl-int-api-date").getValue(), request.getURI().getPath());
String hmacDigest = HmacUtil.generateHmacDigest(stringToSign, secretKey);
request.addHeader("Authorization", String.format("CL-INT-API %s:%s", accessKey, hmacDigest));
HttpResponse response = httpClient.execute(request);
}
Complete Example of a DELETE Request
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.http.HttpResponse;
import org.apache.commons.http.client.HttpClient;
import org.apache.commons.http.client.methods.HttpDelete;
import org.apache.commons.http.impl.client.HttpClientBuilder;
public class HttpMatterDeleteExample {
public static void main (String[] args) throws Exception {
String url = "http://localhost:8090/matter/3A3FB1E6-1F82-4FCE-8E78-91CE16EBB6BF";
String accessKey = "access_key";
String secretKey = "secret_key";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpDelete request = new HttpDelete (url);
request.addHeader ("x-ln-cl-int-api-date", "2020-12-16T18:11:28.577Z");
request.addHeader ("Content-Type", "application/vnd.cl.int.api.v1.0.0+json");
String md5 - DigestUtils.md5Hex("");
request.addHeader ("x-ln-cl-int-api-contentMd", md5);
String stringToSign = HmacUtil.generateStringToSign (request.getMethod(),
"application/vnd.cl.int.api.v1.0.0+json", md5, request.getFirstHeader ("x-ln-cl-int-api-
date").getValue(), request.getURI().getpath());
request.addHeader ("Authorization", String.format("CL-INT-API %s:%s", accessKey,
hmacDigest));
request.addHeader("client_key", accessKey);
HttpResponse response = httpClient.execute(request);
System.out.println(response.getStatusLine().getStatusCode());
}
}
Generate String to Sign -- C# Code Sample
The following C# code snippet shows you how to generate the string that must be signed and the signature to be sent in the Authorization header.
using System.Security.Cryptography;
private string GenerateHmacDigest(string stringToSign, string secretKey) {
string encodedHmacDigest = "";
var encodedKey = Encoding.UTF8.GetBytes(secretKey);
using (var hmac = new HMACSHA256(encodedKey))
{
var encodedStringToSign = Encoding.UTF8.GetBytes(stringToSign);
var hmacDigest = hmac.ComputeHash(encodedStringToSign);
encodedHmacDigest = Convert.ToBase64String(hmacDigest);
}
return encodedHmacDigest;
}
Jump to a sample for String to Sign (C# Code):
Complete Example of a GET Request
HMAC Utility Class
using System;
using System.Security.Cryptography;
using System.Text;
namespace RestExample
{
public static class HmacUtil
{
public static string CalculateMD5Hash(string input)
{
using (var md5 = MD5.Create())
{
var bytes = Encoding.UTF8.GetBytes(input);
var hash = md5.ComputeHash(bytes);
var sb = new StringBuilder();
for (var i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
return sb.ToString();
}
}
public static string GenerateStringToSign(string verb, string contentType, string contentMD5, string iso8601DateTime, string resourcePath)
{
return
verb +
"\n" + contentType +
"\n" + contentMD5 +
"\n" + iso8601DateTime +
"\n" + resourcePath +
"\n";
}
public static string GenerateHmacDigest(string secretKey, string stringToSign)
{
var hmacDigest = "";
var signingKey = Encoding.UTF8.GetBytes(secretKey);
using (var hmac = new HMACSHA256(signingKey))
{
var encodedSignature = Encoding.UTF8.GetBytes(stringToSign);
var signedSignature = hmac.ComputeHash(encodedSignature);
hmacDigest = Convert.ToBase64String(signedSignature);
}
return hmacDigest;
}
public static string BuildAuthorizationString(string accessKey, string hmacDigest)
{
return String.Format("CL-INT-API {0}:{1}", accessKey, hmacDigest);
}
}
}
HTTP GET Example
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
namespace RestExample
{
public static class ExampleGet
{
public static void Run()
{
var apiKey = "access_key";
var privateKey = "secret_key";
var url = "http://localhost:8090";
var resource = "/matter/events";
var queryParam = "?startDate=2024-01-04";
var request = new HttpRequestMessage
{
RequestUri = new Uri(url + resource + queryParam),
Method = HttpMethod.Get
};
var iso8601DateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssK");
var messageSignature = BuildSignature(request.Method.ToString(), "", "", iso8601DateTime, resource);
string base64EncodedSignedSignature = EncodeAndSignSignatureString(privateKey, messageSignature);
string authString = BuildAuthorizationString(apiKey, base64EncodedSignedSignature);
request.Headers.Add("x-ln-cl-int-api-date", iso8601DateTime);
request.Headers.Add("Authorization", authString);
using (var client = new HttpClient())
{
using (var res = client.SendAsync(request).Result)
{
var data = res.Content.ReadAsStringAsync().Result;
Console.WriteLine(data);
}
}
}
private static string BuildSignature(string verb, string contentType, string contentMD5, string iso8601DateTime, string resourcePath)
{
return
verb +
"\n" + contentType +
"\n" + contentMD5 +
"\n" + iso8601DateTime +
"\n" + resourcePath +
"\n";
}
private static string EncodeAndSignSignatureString(string privateKey, string messageSignature)
{
string base64EncodedSignedSignature = "";
var signingKey = Encoding.UTF8.GetBytes(privateKey);
using (var hmac = new HMACSHA256(signingKey))
{
var encodedSignature = Encoding.UTF8.GetBytes(messageSignature);
var signedSignature = hmac.ComputeHash(encodedSignature);
base64EncodedSignedSignature = Convert.ToBase64String(signedSignature);
}
return base64EncodedSignedSignature;
}
private static string BuildAuthorizationString(string apiKey, string base64EncodedSignedSignature)
{
var authString = "CL-INT-API" + " " + apiKey + ":" + base64EncodedSignedSignature;
return authString;
}
}
}
Complete Example of a POST Request
HTTP POST Example
using System;
using System.Net.Http;
using System.Text;
namespace RestExample
{
public static class ExamplePost
{
public static void Run()
{
var accessKey = "access_key";
var secretKey = "secret_key";
var request = new HttpRequestMessage
{
RequestUri = new Uri("http://localhost:8090/matter"),
Method = HttpMethod.Post,
Content = new StringContent(MatterBuilder(), Encoding.UTF8, "application/vnd.cl.int.api.v1.0.0+json")
};
var iso8601DateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssK");
var contentMD5 = HmacUtil.CalculateMD5Hash(request.Content.ToString());
var stringToSign = HmacUtil.GenerateStringToSign(request.Method.ToString(), request.Content.Headers.ContentType.ToString(), contentMD5, iso8601DateTime, request.RequestUri.LocalPath);
var hmacDigest = HmacUtil.GenerateHmacDigest(secretKey, stringToSign);
var authString = HmacUtil.BuildAuthorizationString(accessKey, hmacDigest);
request.Headers.Add("x-ln-cl-int-api-contentmd5", contentMD5);
request.Headers.Add("x-ln-cl-int-api-date", iso8601DateTime);
request.Headers.Add("Authorization", authString);
using (var client = new HttpClient())
{
using (var res = client.SendAsync(request).Result)
{
var data = res.Content.ReadAsStringAsync().Result;
Console.WriteLine(data);
}
}
}
private static string MatterBuilder()
{
return
@"{
""guid"": ""13eed3d8-17fb-447f-bbb2-9b6d9eb945aa"",
""matterNumber"": ""TestMatterNumber"",
""currencyCode"": ""USD"",
""title"": ""Test Matter"",
""matterContactSSOId"": ""USER001"",
""invoiceContactLoginId"": ""USER002"",
""contactOfficeName"": ""LexisNexis"",
""status"" : ""ACTIVE""
}";
}
}
}
Path
The path to be included in HMAC digest is the relative path of the resource and not the absolute path. Any query parameters being used should be removed as well.
Example 1
If the URL being invoked is a matter GUID based fetch (i.e., a GET):
https://api.counsellink.net/matter/84b037ad-1649-4dbe-9c5d-9b6d9eb945aa
The path to be included in HMAC digest generation is:
/matter/84b037ad-1649-4dbe-9c5d-9b6d9eb945aa
Example 2
If an encoded URL for the GET /client/lawfirm/offices/{fieldName}/{vendorId} resource is:
Do not use URL encoding in the path for the HMAC digest.
https://api.counsellink.net/client/lawfirm/offices/Vendor%20ID/V123
The path to be included in HMAC digest generation would be:
/client/lawfirm/offices/Vendor ID/V123
Example 3
If the URL being invoked contains a query parameter, the path is:
The query parameter is not included.
/matters/events?startDate=2024-05-01
The path to be included in HMAC digest would be:
/matters/events