The Common CRM API exposes the members resource of the Link Mobility CRM software, in a RESTful API. Members can be pushed to Link CRM from other software, or it can be pulled from CRM into other software.
Autentication
The API uses HMAC-SHA256 authentication. The request header hmac contains the partnerId, a message signature, the nonce and the timestamp, separated by :. The hmac signature is generated by hashing partnerId, http verb, uri, timestamp, nonce, and an MD5 of the content, if there is any, with SHA256.
Signature parts | How to generate |
---|---|
PartnerId | As provided |
HTTP Method | The HTTP Method of the request |
URI | The absolute uri of the request, lower cased, and then url encoded |
Timestamp | The number of seconds since epoch UTC |
Nonce | A UUID |
Content | If there is a payload on the request, MD5-hash it. |
All of the above parts are concatenated into one string. The UTF8 encoded bytes of the string are then hashed using HMAC-SHA256, using the provided secret key, to generate a signature of the request. This signature is then base-64 encoded.
The header is then built by concatenating the partnerId, the first 10 characters of the encoded signature, the nonce and the timestamp, separated by :.
Sample hmac header
Authorization: hmac 11263:1ObfMLHlvK:2e4603e46dfd489294af13513db02c0a:1453801859 |
Sample C# code for generating the header:
static void Main(string[] args) { var secretkey = "<your base-64 encoded secret key here>"; var partnerId = <your partner id here>; var url = "https://crm-api.linkmobility.com/api/sdk/members/<a valid group id here>/<a valid member id here>"; var method = "GET"; var timestamp = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds); var nonce = Guid.NewGuid().ToString("N"); var data = partnerId + method + WebUtility.UrlEncode(url.ToLower()) + timestamp + nonce; HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(secretkey)); var signedData = hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); var signaturePart = Convert.ToBase64String(signedData).Substring(0, 10); var authHeader = string.Format("hmac {0}:{1}:{2}:{3}", partnerId, signaturePart, nonce, timestamp); Console.WriteLine(signature); Console.ReadLine(); } |
Sample node.js for generating hmac header
const crypto = require('crypto'); const uuid = require('node-uuid'); function generateHmacHeader(sharedSecret, partnerId, httpVerb, uri, requestPayload) { var nonce = uuid.v4(); var timestamp = Math.floor(new Date().getTime() / 1000); var md5Content = ''; if (requestPayload) { md5Content = crypto.createHash('md5'); } var signatureString = partnerId + httpVerb + encodeURIComponent(uri.toLowerCase()) + timestamp + nonce + md5Content; var hmacSignature = crypto.createHmac('SHA256', new Buffer(sharedSecret, 'base64')) .update(signatureString, 'utf8') .digest('base64'); return 'hmac ' + [partnerId, hmacSignature.substring(0, 10), nonce, timestamp].join(':'); } |
Sample python code for generating hmac header (credit: www.skylabs.no)
import uuid import base64 import hashlib import hmac import time import urllib class LinkNext: api_root = 'https://crm-api.linkmobility.com/api/sdk' partnerid = None hmac_key = None def __init__(self, partnerid, hmac_key): self.partnerid = partnerid self.hmac_key = hmac_key.decode('base64') def _generateHMAC(self, uri, http_verb, request = None): nonce = uuid.uuid4().hex string_timestamp = str(int(time.time())) requestmd5 = "" url_encoded = urllib.quote_plus(uri.lower()) if(request): request_json = json.dumps(request) request_bytes = request_json.decode('utf-8') requestmd5 = hashlib.md5(request_bytes).digest().encode('base64').strip() signature_string = '{0}{1}{2}{3}{4}{5}'.format(str(self.partnerid), http_verb, url_encoded, string_timestamp, str(nonce), requestmd5) hmac_signature = hmac.new(self.hmac_key, signature_string, hashlib.sha256) base64_hmac_signature = hmac_signature.digest().encode('base64') hmac_header = '\"{0}:{1}:{2}:{3}\"'.format(str(self.partnerid), base64_hmac_signature[:10], nonce, string_timestamp) header = {'Authorization': 'hmac {0}'.format(hmac_header)} return header |
Sample PHP code example for generating HMAC header
<?php $partner_id = '<your partner id>'; // from LINK Mobility $secret_key = '<your secret key>'; // from LINK Mobility $secret_key = base64_decode($secret_key); # EXAMPLE generating HMAC for GET request to api/sdk/members/<groupId><memberId> $request_method = strtoupper("GET"); $url = 'https://crm-api.linkmobility.com/api/sdk/members/771/08F8DCB2-21CA-4661-B6DD-3F553C5449FD'; $url = strtolower($url); $request_content = ''; $auth_header = getAuthHeader($partner_id, $secret_key, $request_method, $url, $request_content); echo $auth_header; // display the Authorization: header to be included in the request function getAuthHeader($partner_id, $secret_key, $request_method, $url, $request_content) { # generate Authorization Header $requestUri = urlencode($url); $requestTimeStamp = time(); // current UNIX timestamp $nonce = uniqid(); // string if ( !empty($request_content) ) { $requestContentMd5Hash = md5($request_content, true); /* raw binary format with length of 16 */ } else { $requestContentMd5Hash = $request_content; } $request_content = base64_encode($requestContentMd5Hash); $signatureRawData = ($partner_id . $request_method . $requestUri . $requestTimeStamp . $nonce . $request_content ); $utf8_data = utf8_encode($signatureRawData); $hmac_before_base64 = hash_hmac ( 'sha256', $utf8_data , $secret_key, true ); // not raw digital output $hmac_base64_encoded = base64_encode ( $hmac_before_base64); $hmac_substringed = mb_substr ( $hmac_base64_encoded, 0, 10, 'UTF-8' ); $auth_header = "Authorization: hmac $partner_id:$hmac_substringed:$nonce:$requestTimeStamp"; return $auth_header; } ?> |
Base URL
https://crm-api.linkmobility.com/api/sdk/
Formats
The response from GET requests will by default be formatted as XML. If you prefer to use JSON, you can append the following to the URI: ?$format=json.
GET /members/{groupId}/{memberId}
Gets the member information by providing the groupId and the internal member id.
URI params
Name | Description |
---|---|
groupId | An existing Link CRM groupId (internal) |
memberId | An existing Link CRM memberId (internal) |
Sample response
{ "memberId":"86435f0f-bd85-418c-9c74-fa985068c1b4", "active":true, "groupId":481, "externalId":null, "msisdn":"45066506", "countryCode":"47", "firstName":"Kjersti", "lastName":"Berg", "streetAddress":"Gaustadalléen 21", "zipCode":"0349", "city":"Oslo", "location":{ "latitude":59.942219906222, "longitude":10.715902555317 }, "birthDate":null, "gender":1, "email":null, "regDateUtc":"2016-01-25T13:19:00Z", "modifiedByUserDateUtc":null, "daysSinceRegistration":1, "minutesSinceRegistration":1235, "hasBirthDay":false, "modifiedByUser":false, "customProperties":null } |
GET /members?groupId={groupId}&externalId={externalId}
Query params
Name | Description |
---|---|
groupId | An existing Link CRM groupId (internal) |
externalId | An existing Link CRM member externalId |
Sample response
{ "memberId":"86435f0f-bd85-418c-9c74-fa985068c1b4", "active":true, "groupId":481, "externalId":"abc123", "msisdn":"45066506", "countryCode":"47", "firstName":"Kjersti", "lastName":"Berg", "streetAddress":"Gaustadalléen 21", "zipCode":"0349", "city":"Oslo", "location":{ "latitude":59.942219906222, "longitude":10.715902555317 }, "birthDate":null, "gender":1, "email":null, "regDateUtc":"2016-01-25T13:19:00Z", "modifiedByUserDateUtc":null, "daysSinceRegistration":1, "minutesSinceRegistration":1235, "hasBirthDay":false, "modifiedByUser":false, "customProperties":null } |
GET /members?groupId={groupId}&countryCode={countryCode}&msisdn={msisdn}
Lookup a member resource by MSISDN.
Query params
Name | Description |
---|---|
groupId | An existing Link CRM groupId (internal) |
countryCode | Country code of the member phone number, i.e. 47. |
msisdn | Member phone number, i.e. 99999999 |
Sample response
{ "memberId":"86435f0f-bd85-418c-9c74-fa985068c1b4", "active":true, "groupId":481, "externalId":null, "msisdn":"45066506", "countryCode":"47", "firstName":"Kjersti", "lastName":"Berg", "streetAddress":"Gaustadalléen 21", "zipCode":"0349", "city":"Oslo", "location":{ "latitude":59.942219906222, "longitude":10.715902555317 }, "birthDate":null, "gender":1, "email":null, "regDateUtc":"2016-01-25T13:19:00Z", "modifiedByUserDateUtc":null, "daysSinceRegistration":1, "minutesSinceRegistration":1235, "hasBirthDay":false, "modifiedByUser":false, "customProperties":null } |
POST /members
Creates a new member. The payload is an XML or JSON formatted representation of the new member resource.
Data | Description |
---|---|
Msisdn | The member phone number, not including country code. E.g. 99999999 |
CountryCode | The member phone number country code, E.g. 47 |
GroupId | Link CRM groupId. |
ExternalId | Optional. Can be used to link to an Id in an external system. |
FirstName | Optional. The member's first name. |
LastName | Optional. The member's last name. |
StreetAddress | Optional. The member's street address. |
ZipCode | Optional. The member's zip code. |
City | Optional. The member's city. |
Location | Optional. The member's geolocation, specified with latitude and longitude. E.g. { latitude: 51.5034070, longitude: -0.1275920 } |
BirthDate | Optional. The member's birth date. |
Gender | The member's gender. 0 = unspecified, 1 = female, 2 = male. |
Optional. The member's email. | |
CustomProperties | Optional. In Link CRM there is an option to attach custom properties to member resources. These must be defined in Link CRM to be used in the API. |
Sample response
HTTP/1.1 201 Created Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: * Access-Control-Expose-Headers: Location Content-Length: 0 Date: Tue, 26 Jan 2016 10:03:11 GMT Location: https://crm-api.linkmobility.com/api/members/a7247840-95c5-479d-954a-de492e564650 Server: Microsoft-IIS/8.0 X-Powered-By: ASP.NET |
PUT /members/{groupId}/{memberId}
Updates an existing member.
URL params
groupId | An existing Link CRM groupId (internal) |
memberId | An existing Link CRM memberId (internal) |
The updated member resource is included in the request body, as XML or JSON. Set the appropriate content-type in the request header.
The payload will replace the existing member resource identified by that memberId.
Sample response
HTTP/1.1 204 No content Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: * Access-Control-Expose-Headers: Location Content-Length: 0 Date: Tue, 26 Jan 2016 11:22:02 GMT Server: Microsoft-IIS/8.0 X-Powered-By: ASP.NET |
Error codes
Code | Result |
---|---|
401 Hmac timestamp clock-drift too high | The timestamp used to generate the hmac token is too old. |
401 Invalid HMAC | The hmac token in the Authorization header has some invalid content. |
400 Member id <id> not found | The provided memberId does not exist |
400 Group id <id> not found | The provided groupId does not exist |