Learn how monitor and store the user-generated content flowing through the Livefyre system.
Use the Activity Stream API to consume user generated data flowing through the Livefyre system on your network or site. For example: use data from this API to update your search indices based on ratings, or to manage users’ badges in a 3rd party system based on their activity.
Activity Stream API:
For a complete list of available endpoints, please see the Livefyre API Reference section.
There are two endpoints, one for the staging environment, and one for production.
GET https://bootstrap.t402.livefyre.com/api/v3.1/activity/
GET https://bootstrap.livefyre.com/api/v3.1/activity/
resource: string A URN of the object for which you are requesting activity data.
since: integer A 64-bit integer representing the the ID of the last event you received. Specify ‘0’ if you have no prior data.
Examples:
example.fyre.co
The activity stream for example.fyre.co
.example.fyre.co:site=54321
The activity stream for site 54321 under the example.fyre.co
network.The Activity Stream API uses an OAuth Bearer Token for authentication. Bearer Tokens are part of the OAuth 2.0 specification, and officially described here.
A token contains several things:
The steps to create an OAuth Bearer Token include:
The code sample below demonstrates the above steps in Python:
import time
import jwt
# network data goes here:
network = "timeout-0.fyre.co"
network_secret = "...replaceme..."
# api URN
api_urn = "urn:livefyre:api:core=GetActivityStream"
# expires in 10 seconds
expiration = int(time.time() + 10)
network_urn = "urn:livefyre:" + network
data = dict(iss=network_urn, aud=network_urn, sub=network_urn, scope=api_urn, exp=expiration)
token = jwt.encode(data, key=network_secret)
Where the bearer token keys are defined as follows:
curl -H "Authorization: Bearer <BEARER TOKEN>" https://bootstrap.livefyre.com/api/v3.1/activity/?resource=&since=
{
"code": 200,
"data": {
"annotations": {},
"authors": {
/** "a set of every author who generated activity within this window" */
"_up1770425@livefyre.com": {
"avatar": "https://gravatar.com/avatar/68c789597150d3e941769a5c0a0c4249/?s=50&d=https://avatars-qa.fyre.co/a/anon/50.jpg",
"displayName": "ross_pfahler",
"id": "_up1770425@livefyre.com",
"profileUrl": "https://www.qa-ext.livefyre.com/profile/1770425/",
"tags": [],
"type": 1
},
...
},
"collections": {
/** "a set of every collection for which an activity was generated" */
"2486601": {
"articleIdentifier": "75",
"id": "2486601",
"site": "290596",
"title": "Live Blog",
"url": "https://orangesaregreat.com/..."
},
...
},
/** "the maximum event ID for this window" */
"maxEventId": 1383508243715211,
"states": {
/** "a set of messages (comments, reviews, etc) for which activity
was generated in this window, represents the compiled
'state' of the object including visible actions on that object
(up-votes, likes, and etc.)" */
"3ad6480eb00c4895b29b7a972380f489@livefyre.com": {
"collectionId": "2486685",
"content": {
"annotations": {
"rating": [ 90 ], /** "this object is a Rating (4.5)" */
"vote": [
{
"author": "_up1792695@livefyre.com",
"collectionId": "2486685",
"value": 1
}
]
},
"attachments": [
/** "a list of oembeds; the body of this Rating included
this Youtube video" */
{
"author_name": "mauricio890",
"author_url": "https://www.youtube.com/user/mauricio890",
"height": 480,
"html": "<iframe width=\"854\" height=\"480\" src=\"https://www.youtube.com/embed/pmMAw5a7POU?autoplay=1&feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
"link": "https://www.youtube.com/watch?v=pmMAw5a7POU",
"provider_name": "YouTube",
"provider_url": "https://www.youtube.com/",
"thumbnail_height": 360,
"thumbnail_url": "https://i1.ytimg.com/vi/pmMAw5a7POU/hqdefault.jpg",
"thumbnail_width": 480,
"title": "Napoleon Dynamite dance scene",
"type": "video",
"url": "https://www.youtube.com/watch?v=pmMAw5a7POU",
"version": "1.0",
"width": 854
}
],
// "who authored the content"
"authorId": "_up1793160@livefyre.com",
"bodyHtml": "<p><strong>Pros:</strong>Boom</p><p><strong>Cons:</strong>Goes</p><p><strong>Description:</strong>The dynamite:</p><p><a href=\"https://www.youtube.com/watch?v=pmMAw5a7POU\" target=\"_blank\" rel=\"nofollow\">https://www.youtube.com/watch?v=pmMAw5a7POU</a><br/></p>",
// "UNIX timestamp"
"createdAt": 1383257354,
"id": "3ad6480eb00c4895b29b7a972380f489@livefyre.com",
// "non-empty only if this were a reply"
"parentId": "",
// "UNIX timestamp"
"updatedAt": 1383257356
},
// "the event ID of this state."
"event": 1383369320554187,
"lastVis": 3,
"source": 0,
"type": 0,
// "Object visibility: 0 = deleted, 1 = everyone, 2 = bozo,
// 3 = owner + admins (e.g. premod)"
"vis": 1
},
"5943789": {
"collectionId": "2486688",
"content": {
"annotations": {
// "posted by a moderator"
"moderator": true
},
"authorId": "_up1792872@livefyre.com",
"bodyHtml": "<p>This is a regular comment from a moderator</p>",
"createdAt": 1383372338,
"id": "5943789",
"parentId": "",
"updatedAt": 1383372338
},
"event": 1383372338732492,
"lastVis": 0,
"source": 5,
"type": 0,
"vis": 1
},
"863c616a2c0c44239feed0914c282d7c@livefyre.com": {
"collectionId": "2486685",
"content": {
"id": "863c616a2c0c44239feed0914c282d7c@livefyre.com"
},
"event": 1383371303805767,
"lastVis": 1,
"source": 0,
"type": 0,
"vis": 0 // "0 = deleted; this object was removed"
},
...
},
"meta": {
// "this describes position in the stream"
"cursor": {
// "maximum number of objects returned in a single call through this API"
"limit": 50,
// "the final position in the stream, and from where data should be requested"
"next": 1383508243715211,
// "the initial position (the 'since' parameter value in this request)"
"self": 0
}
},
"status": "ok"
}
A response with new data since the last request:
{
"code": 200,
"data": {
"annotations": {},
"authors": {},
"collections": {},
"maxEventId": -1,
"states": {}
},
"meta": {
"cursor": {
"limit": 50,
/** "indicates there is no data beyond 1383508243715211" */
"next": null,
"self": 1383508243715211
}
},
"status": "ok"
}
data.meta.cursor.next
as the since
parameter of your next request.data.meta.cursor.next
is null, it means there is no new data to consume. You should re-request later with the same since
value to see if new data has arrived.data.meta.cursor.next
value is non-null.