Compliance Events API
Important
Documentation Updates: We have made some structural changes to the left navigation to create a logical grouping of topics. Following are the changes:
- The Integration section is now available under Compliance Snapshot Overview API.
- Compliance Event API and Compliance Snapshot API are now separate sections containing the respective topics within it.
The Compliance Events API allows you to archive all LinkedIn activities from the past 30 days of a regulated, authenticated member. It returns each monitored activity as an individual event record to provide ease of archive and remediation if necessary.
Note
All use of the Microsoft Bing Maps location data is subject to Microsoft Bing Maps and MapPoint Web Service End User Terms of Use and Embedded Maps Service Terms of Use and the Microsoft Privacy Statement. By accessing any Microsoft Bing Maps location data, you are agreeing to be bound by these Microsoft terms.
Additional Decoration Activities
Usage
You must use an access token to make an authenticated call on behalf of a user.
Permissions
Permission | Description |
---|---|
r_compliance | Required to retrieve activities for compliance monitoring and archiving. |
To use the following APIs, you will need to know your application ID
. This can be found in your Developer Application Setting page. Select your application and go to the Mobile section to view your application ID
. Alternatively, you can find the ID from the URL as well (ie. https://www.linkedin.com/developer/apps/{applicationID}/auth)
.
Compliance Authorization
To begin monitoring a member's activities, you will need to opt in the member into our Compliance system by calling the following API:
POST
https://api.linkedin.com/v2/memberComplianceAuthorizations
Note
You will need to supply an empty JSON object, {}
to the request body to successfully opt the member into compliance.
Once the member has been opted in, all activities performed will be captured by the Compliance Events API . The API will not contain any preceding activities and will only capture activities performed following the authorization toggle. You can check the member's authorization status by requesting the following member FINDER
API:
GET
https://api.linkedin.com/v2/memberComplianceAuthorizations?q=member&projection=(elements*(memberComplianceAuthorizationKey(developerApplication,member~(firstName,lastName,headline)),regulatedAt))
sample GET response
{
"elements": [
{
"memberComplianceAuthorizationKey": {
"developerApplication": "urn:li:developerApplication:123456",
"member": "urn:li:person:123ABC",
"member~": {
"firstName": {...},
"lastName": {...},
"headline": {...}
}
},
"regulatedAt": {
"created": 1476375405722,
"lastModified": 1476375405722
}
}
]
}
If the response contains your own developerApplicationUrn
, then you are good to go!
Note
The sample request above is utilizing projection to decorate member with more information. This not needed as the member returned is always the one represented by the access token. However, this example represents decoration use if you choose to utilize it.
Compliance De-Authorization
If you wish to have LinkedIn stop monitoring a regulated member's activities i.e. opt out the member from our Compliance Platform, call the following and all subsequent member activities performed on LinkedIn will not be captured.
To allow developers to De-Authorize members for whom the access token might have expired, the following API can also be used with access tokens obtained via OAuth2.0 Client Credentials flow.
DELETE https://api.linkedin.com/v2/memberComplianceAuthorizations/developerApplication={developerApplicationURN}&member={personURN}
Note
A member will not opt out of Compliance authorization due to access token expiration. The only ways an opt out can happen are:
- Application invokes the DELETE API mentioned above
- The regulated member removes the application's authorization through LinkedIn's Privacy Setting page. This can be found under the Third Parties section.
Therefore, it is always a good idea to periodically check the member's authorization status using the GET API.
Compliance Events
After the member is authorized, you can start archiving the activities performed with the following request:
GET
https://api.linkedin.com/v2/complianceEvents?q=memberAndApplication&projection=(elements*(id,capturedAt,processedAt,configVersion,owner~(firstName,lastName,headline),actor~(firstName,lastName,headline),resourceName,resourceid,resourceUri,method,activity,processedActivity,siblingActivities,parentActivity,parentSiblingActivities),paging)
Query Parameters
Field Name | Required | Description |
---|---|---|
startTime | No | Represented as an inclusive timestamp in epoch milliseconds. If present, returns all the activities that are processed after the time. |
Note
We recommend you specifying startTime
by using the latest processedAt
from the previous response. If there is no event from the previous response, keep the same startTime
for the next request. If there is an event from the response, the next request should use the latest timestamp of the processedAt
and that event will show up on the next request's response. This way, we will ensure no data loss in the next API request.
We currently return events up to 30 days. If you specify a startTime
older than 30 days of the current timestamp, it will return events up to 30 days. If you specify an invalid timestamp, it will throw a 400 error.
In addition, we recommend querying at a count=10
to reduce latency and to query each member's activities once an hour. The upper limit is 50
. If you set a number not in the range [1,50]
, it will result in a 400
and an error message containing the recommended count
.
If you decide to increase number of activities returned via count
, keep in mind it will slow down processing time and can lead to timeouts. For querying each member's activities, we recommend spreading out your requests over the hour such that your application is not having QPS spikes, which could lead to timeouts as well.
We also recommend using the capturedAt time returned by Compliance Events API to determine the time of the event activity. There might be instances within the specific activity that do not return the created/lastModified time.
The Compliance Events API will return an array of elements. Each element is an activity record with the following schema:
Compliance Events Schema
Field Name | Description |
---|---|
id | The unique identifier for the activity event. |
capturedAt | Time the event is captured. |
processedAt | Time the event is processed. |
configVersion | The configuration version used to process this event. This is unique to the activity's resourceName and method. It can change periodically as we update our configurations to better the API experience. It will mainly used for debugging purpose. |
owner | The member who owns the record. It is the same member who has retrieval and viewing access to this activity. |
actor | The member who performs the action of the activity. |
resourceName | Name of resource being acted upon. Please refer below for a complete list of the resources being captured. |
resourceId | The identifier of the resource. |
resourceUri | URI of the resource being modified. Used for remediation. |
method | The resource method. Can be one of the following write methods: *As of now, if a method is DELETE, the activity and processedActivity fields should be empty since we cannot capture the object after it has been deleted. |
methodName | The optional string representing the method's name. Only present in ACTION method. |
activity | The original activity data. Used for remediation. |
processedActivity | The decorated original activity containing relevant contextual information. For example, if the original activity is a comment, this will include the original share content. Used for archiving. |
siblingActivities | The activities on the same resource level. This is used for previous sibling comments on a share or previous messages in a conversation. Will return up to 10 most recent previous activities. |
parentSiblingActivities | The previous activities on the parent resource level. Example would be the previous sibling comments of a parent comment of a nested comment. Will return up to 10 most recent previous activities. |
activityId | A unique string identifier of a captured activity. If an activity is processed more than once, all generated records share same activityId. |
activityStatus | NEW! The status of the event. Can be one of the following:
|
Sample Get Response
{
"elements": [
{
"id": 100,
"activityId": "12356788990000",
"capturedAt": 1476375751786,
"processedAt": 1476375771769,
"configVersion": 1,
"owner": "urn:li:person:123ABC",
"owner~": {
"firstName": {
"localized": {
"en_US": "John"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"lastName": {
"localized": {
"en_US": "Smith"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"headline": {
"localized": {
"en_US": "Staff Software Engineer"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
}
},
"actor": "urn:li:person:123ABC",
"actor~": {
"firstName": {
"localized": {
"en_US": "John"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"lastName": {
"localized": {
"en_US": "Smith"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"headline": {
"localized": {
"en_US": "Staff Software Engineer"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
}
},
"resourceName": "people/positions",
"resourceId": "123ABC",
"resourceUri": "/people/id=123ABC/positions",
"methods": "PARTIAL_UPDATE",
"activity": {
"patch": {
"$set": {
"startMonthYear": {
"month": 3,
"year": 2014
},
"title": {
"localized": {
"en_US": "Software Developer"
}
},
"company": "urn:li:company:0000"
}
}
},
"processedActivity": {
"patch": {
"$set": {
"startMonthYear": {
"month": 3,
"year": 2014
},
"title": {
"localized": {
"en_US": "Software Developer"
}
},
"company": "urn:li:company:0000",
"company~": {
"name": "LinkedIn",
"description": "Awesome Company!"
}
}
}
}
},
{
"id": 101,
"capturedAt": 1476375771786,
"processedAt": 1476375971769,
"configVersion": 1,
"owner": "urn:li:person:123ABC",
"actor": "urn:li:person:123ABC",
"resourceName": "endorsement",
"resourceId": "123456",
"resourceUri": "/endorsements/123456",
"methods": "CREATE",
"activity": {
"item": {
"nonStandardEntity": {
"entityType": "PROFILE_SKILL",
"entityPhrase": "Java",
}
},
"endorser": "urn:li:person:123ABC",
"recipient": "urn:li:person:456DEF",
"location": "skills.section"
},
"processedActivity": {
"item": {
"nonStandardEntity": {
"entityType": "PROFILE_SKILL",
"entityPhrase": "Java",
}
},
"endorser": "urn:li:person:123ABC",
"endorser~": {
"lastName": {
"localized": {
"en_US": "Smith",
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"firstName": {
"localized": {
"en_US": "Bob",
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"headline": {
"localized": {
"en_US": "Software Engineer at LinkedIn",
},
"preferredLocale": {
"country": "US",
"language": "en"
}
}
},
"recipient": "urn:li:person:456DEF",
"recipient~": {
"lastName": {
"localized": {
"en_US": "Johnson",
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"firstName": {
"localized": {
"en_US": "Joe",
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"headline": {
"localized": {
"en_US": "Senior Software Engineer",
},
"preferredLocale": {
"country": "US",
"language": "en"
}
}
},
"location": "skills.section"
}
},
...
],
"paging": {
"count": 10,
"start": 0,
"links": [
{
"rel": "next",
"href": "/v2/complianceEvents?count=10&projection=%28elements*%28id%2CcapturedAt%2CprocessedAt%2CconfigVersion%2Cowner%7E%28firstName%2ClastName%2Cheadline%29%2Cactor%7E%28firstName%2ClastName%2Cheadline%29%2CresourceName%2Cresourceid%2CresourceUri%2Cmethods%2Cactivity%2CprocessedActivity%2CsiblingActivities%2CparentActivity%2CparentSiblingActivities%29%2Cpaging%29&q=memberAndApplication&start=10",
"type": "application/json"
}
]
}
}
Each activity record contains metadata such as resourceName
, resourceId
, resourceUri
, and more to help you identify the activity performed so you can properly archive and remediate as needed.
As best practice, we recommend archiving all the data but specifically method
, resourceName
, resourceId
, configVersion
and processedActivity
. For remediation, you will be able to use resourceUri
and activity
to easily update what is needed.
Resource References
The following resources are currently being captured and supported as part of Compliance Events:
- People
- Endorsement
- Recommendation
- Publishing Articles
- UGC Posts
- Social Actions
- Organizations
- Invitations
- Messages
Entity Monitoring
We added this feature to monitor activities that does not reference the regulated member directly. The activities returned will be related to the regulated member but not directly associated or performed by the regulated member. To know more, refer here.
Error Handling
In the event that a field or an activity is unable to be processed, we will still return the activity such that you are notified that an activity has occurred. The field that is not processed will have following message of "Unable_to_process_this_field."
. In the processedActivity
, the whole activity can be unprocessed, which will result in string of "message": "Unable to process this event."
. If a particular field in the processedActivity is unprocessed, then it will have !
and the string "message": "Unable to process this field."
. See below for examples.
Unable to process a field
{
"activity": {},
"activityId": "81fafbe1-ea4b-4454-a736-6b8a20d9aa90",
"actor": "urn:li:person:sFrA4B1w3F",
"capturedAt": 1494367986523,
"configVersion": 2,
"id": 23260,
"method": "UPDATE",
"owner": "urn:li:person:sFrA4B1w3F",
"processedActivity": {
"message": "Unable to process this event."
},
"processedAt": 1494368009776,
"resourceId": "Unable_to_process_this_field.",
"resourceName": "mockSimpleKeyCollection",
"resourceUri": "Unable_to_process_this_field."
}
unable to process an activity
{
"activity": {
"simpleUnionField": {
"int": 3
},
"urn": "urn:li:person:sFrA4B1w3F"
},
"activityId": "b77d27f4-b7c9-426c-a43e-204a2735c798",
"actor": "urn:li:person:sFrA4B1w3F",
"capturedAt": 1494368763168,
"configVersion": 2,
"id": 23716,
"method": "UPDATE",
"owner": "urn:li:person:sFrA4B1w3F",
"processedActivity": {
"message": "Unable to process this event."
},
"processedAt": 1494369845019,
"resourceId": "4",
"resourceName": "mockSimpleKeyCollection",
"resourceUri": "/mockSimpleKeyCollection/4"
}
Unable to process an urn field in processedActivity
{
"activity": {
"simpleUnionField": {
"int": 3
},
"urn": "urn:li:person:sFrA4B1w3F"
},
"activityId": "81fafbe1-ea4b-4454-a736-6b8a20d9aa90",
"actor": "urn:li:person:sFrA4B1w3F",
"capturedAt": 1494367986523,
"configVersion": 2,
"id": 23260,
"method": "UPDATE",
"owner": "urn:li:person:sFrA4B1w3F",
"processedActivity": {
"simpleUnionField": {
"int": 3
},
"urn": "urn:li:person:sFrA4B1w3F",
"urn!": {
"message": "Unable to process this field."
}
},
"processedAt": 1494368009776,
"resourceId": "4",
"resourceName": "mockSimpleKeyCollection",
"resourceUri": "/mockSimpleKeyCollection/4"
}
Replayer Feature
Replayer feature provides the ability to reprocess events that have already occurred and surfaced on the API response. This feature will provide more information on past activities that were not previously available during the initial compliance capture and process by surfacing them on new events. The Replayer feature will not modify existing events, only create new ones corresponding to the same activty. This feature will go live on February 12, 2020 with the goal of reprocessing all events that have missing and/or incomplete data.
Starting on February 12, 2020, you may see reprocessed events in the Compliance Events API response. To differentiate between initial and reprocessed events, we are introducing activityStatus
field to denote each event's process state. It can be one of the following: SUCCESS
, FAILURE
, or SUCCESSFUL_REPLAY
. To prevent archiving duplicate events, partners can filter out reprocessed events by filtering out SUCCESSFUL_REPLAY
events until they are ready to utilize this feature.
Currently, reprocessed events will only appear in the API response if it's successfully reprocessed with no processing failures. This means the maximum number of Compliance Events for a unique activity is two. Therefore the three possible scenarios are:
- Event with
SUCCESS
activityStatus. - Event with
FAILURE
activityStatus with no subsequent event. - Event with
FAILURE
activityStatus that eventually is followed by another event withSUCCESSFUL_REPLAY
activityStatus.
Some other ways to identify and differentiate these activities are to use the following fields: id
, activityId
, and processedAt
. For more information on these fields, refer to the Compliance Events Schema. See below for an example:
Sample Replay Activities
{
"elements": [
{
"id": 1000,
"owner": "urn:li:person:yrZCpj2ZYQ",
"resourceId": "urn:li:ugcPost:123456789",
"configVersion": 36,
"method": "CREATE",
"activity": {
"author": "urn:li:person:yrZCpj2ZYQ",
"id": "urn:li:ugcPost:123456789",
...
},
"resourceName": "ugcPosts",
"resourceUri": "/ugcPosts/urn:li:ugcPost:123456789",
"actor": "urn:li:person:yrZCpj2ZYQ",
"activityId": "8561f816-517e-49fb-901d-29c589e3b09f",
"processedAt": 1572831764582,
"capturedAt": 1573079762090,
"activityStatus": "FAILURE",
"processedActivity": {
"author": "urn:li:person:yrZCpj2ZYQ",
"author!": {
"message": "Unable to process this field."
},
"id": "urn:li:ugcPost:123456789",
...
}
},
{
"id": 1001,
"activityStatus": "SUCCESS",
...
},
{
"id": 1002,
"activityStatus": "SUCCESS",
...
},
{
"id": 1003,
"activityStatus": "SUCCESS",
...
},
{
"id": 1004,
"owner": "urn:li:person:yrZCpj2ZYQ",
"resourceId": "urn:li:ugcPost:123456789",
"configVersion": 37,
"method": "CREATE",
"activity": {
"author": "urn:li:person:yrZCpj2ZYQ",
"id": "urn:li:ugcPost:123456789",
...
},
"resourceName": "ugcPosts",
"resourceUri": "/ugcPosts/urn:li:ugcPost:123456789",
"actor": "urn:li:person:yrZCpj2ZYQ",
"activityId": "8561f816-517e-49fb-901d-29c589e3b09f",
"processedAt": 1573759549000,
"capturedAt": 1573079762090,
"activityStatus": "SUCCESSFUL_REPLAY",
"processedActivity": {
"author": "urn:li:person:yrZCpj2ZYQ",
"author~": {
"firstName": {
"localized": {
"en_US": "Bob"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
...
},
"id": "urn:li:ugcPost:123456789",
...
}
}
]
}
Note
Notice the first and last event in the above sample response and their specific fields: activityStatus
, id
, activityId
, and processedAt
. The activityStatus
field helps determine whether or not it's a reprocessed event and the last event denotes a reprocessed event. In addition, the two events correspond to the same activity by having the same activityId
. However, they have different unique id
and the first activity has the previous processedAt
timestamp while the last one has the latest timestamp. The last activity was not able to process the author
decoration in processedActivity
and has author!
whereas the first activity reprocessed the field with author~
in processedActivity
. For more information on response decoration, please refer here.