Skip to main content

Content Service

The content service is responsible for content related to education in the LifeOmic API. It powers the LifeOmic Platform Programs feature, which allows you to build an interactive learning program for subjects. This educational program is delivered with the LifeOmic mobile app. Content service offers course creation related functions, such as putting content in a draft or published state.

You can also attach media assets to a course. This involves the two types of content service data, content and file. Content data is structured JSON describing an educational component, such as a course or course day. File data is the actual file related to the content, such as mp3, png, or pdf files.

note

Content service is intended for educational content. It does not encrypt files and is not HIPAA compliant. Use the files service if you need HIPAA compliance and encrypted file handling.

Getting Started with the Content Service API

This guide walks you through using the content service for these basic operations:

For content service endpoint details, see the API Reference Information. For authentication and other basic operations with the LifeOmic API, see Getting Started.

List Content

Use GET https://api.us.lifeomic.com/v1/content/{projectId}/content to list all the content for your LifeOmic project. This command uses the projectId parameter to specify the project. To find the <project-id>, see Find the Project ID.

List Content Call Example

This cURL example uses the projectId parameter to specify the project:

curl --location 'https://api.us.lifeomic.com/v1/content/<projectId>/content' \
--header 'LifeOmic-Account: <account-id>' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <api-key>'

Response to List Content Call

The content call returns a JSON response that lists the education items and includes a content ID, display name, type, status, and other fields for each item. The Programs feature in the LifeOmic Platform relies on these fields for the user interface presentation. In the below screenshot, you can see the Courses category contains a course titled Get Eating Healthy. This information is derived from the type and displayName items contained in the list content response. These lines are highlighted in the response example below the screenshot.

Content Service UI

Response to List Content Call Example with nextPageToken

This response highlights the displayName and type values.

{
"items": [
{
"id": "f968d237-73c6-46cf-814e-5f040b7af494",
"project": "<projectId>",
"displayName": "Get Eating Healthy",
"type": "course",
"fields": {
"description": {
"value": "learning about meditation"
},
"duration": {
"value": 7
},
"daySlugs": {
"value": [
"390fdc3d-3078-43dd-9387-48caa4978b1e",
"0660c507-b1a4-4e71-827f-984189d9acc6",
"2dda07cc-908e-4fb1-a862-fb51b8354e1a",
"bff73e02-257d-4b37-97fe-b96fbe9103b2",
"c5532546-aa23-4b8b-b2c9-85ab60826f19",
"37bab494-b226-4248-8651-f5a58a930091",
"c3e98713-b2d7-4fb7-9fc0-c1f1e6ec23ff"
]
},
"isPristine": {
"value": false
}
},
"slug": "1defb12c-daae-42f2-b13c-b9d010ef8c45",
"keyPath": "meditation-program-99823e2d-5cef-4990-af00-f92cafc8fd07/1defb12c-daae-42f2-b13c-b9d010ef8c45",
"status": "draft",
"isDirty": true,
"lastModified": "2022-10-12T19:45:43.795Z",
"account": "<account-id>"
},
],
"links": {
"self": "/v1/content/<projectId>/content",
"next": "/v1/content/<projectId>/content?nextPageToken=eyJwcm9qZWN0IjoiZWJlMTYxOGYtZTQ3NC00OTQ3LWE2ZDItMThiMTlmYWM2NjNhIiwiaWQiOiJsaWZlb21pYzowNjAwYzNmNC02YTM5LTQ2NjktOGU1MC0zZjMxNDU5NWEzMmQiLCJyb3dUeXBlIjoiY29udGVudDpsaWZlb21pYzowNjAwYzNmNC02YTM5LTQ2NjktOGU1MC0zZjMxNDU5NWEzMmQiLCJ0eXBlIjoicHJvZ3JhbSJ9"
}
}

Large Numbers of Content Items

A project can have too many content items to be listed in a simple response. If more items exist than can be contained in the response, a nextPageToken appears in the last line of the response, as highlighted in the JSON example above.

If you receive a nextPageToken in your response, you use the same techniques that are used in the Parameters to Help Manage a Large Number of Files to work with a large number of content items.

List a Specific Content Item

To show a specific content item, you make another Get Content call. This time you add the id from your earlier response.

Example of List a Specific Content Item Call

curl --location 'https://api.us.lifeomic.com/v1/content/<projectId>/content/<contentId>' \
--header 'LifeOmic-Account: <account-id>' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <api-key>'

Response to List a Specific Content Item Call

In addition to the information contained in the response from the general list call, the response to the specific list call contains fileAttachments and contentAttachments keys. A file attachment creates the relationship between content and supporting files. It also optimizes browser rendering and provides checks for accidental deletion. Content attachments perform a similar role to file attachments, but they reference content slugs instead of file IDs.

This response highlights the fileAttachments and contentAttachments values.

{
"id": "<contentId>",
"project": "<projectId>",
"displayName": "Get Mindful",
"type": "course",
"fields": {
"description": {
"value": "Learn about meditation"
},
"duration": {
"value": 7
},
"daySlugs": {
"value": [
"fce28b1f-4d69-488f-903a-433ea6e805dc",
"15fc6713-c3bb-481b-8154-4a46d2903223",
"7cf9c432-ef92-4c5b-ab12-438cf0d23b92",
"8caa081c-ba70-4174-9657-19e693b041e0",
"fa7fff5c-ba70-4fe4-8a6f-9304fea75621",
"0cf4e478-c3a5-494c-bf4b-bfa28bfbc19c",
"b06820c9-dbf1-4965-a240-2b8b0d02397e"
]
},
"isPristine": {
"value": false
}
},
"slug": "get-mindful-a30fecda-fe23-4101-98f8-89a367d9c752",
"keyPath": "meditation-program-99823e2d-5cef-4990-af00-f92cafc8fd07/get-mindful-a30fecda-fe23-4101-98f8-89a367d9c752",
"status": "draft",
"isDirty": true,
"lastModified": "2023-03-06T22:55:00.062Z",
"account": "lifeomic",
"fileAttachments": [],
"contentAttachments": [
{
"project": "ebe1618f-e474-4947-a6d2-18b19fac663a",
"parentId": "692470f5-42cc-467f-b05c-ba33da51c5c7",
"childSlug": "0cf4e478-c3a5-494c-bf4b-bfa28bfbc19c",
"parentType": "course",
"childType": "courseDay",
"meta": {}
},
{
"project": "ebe1618f-e474-4947-a6d2-18b19fac663a",
"parentId": "692470f5-42cc-467f-b05c-ba33da51c5c7",
"childSlug": "15fc6713-c3bb-481b-8154-4a46d2903223",
"parentType": "course",
"childType": "courseDay",
"meta": {}
}
]
}

Delete Content

To delete content, you make a DELETE call and include the contentId. This is the 32-digit id value in the first line of each item entry in the GET content response. A successful deletion returns a 204 (No Content) response with an empty response body.

Published content may not be directly deleted, it must be unpublished first. To unpublish, see Publish Content.

Example of Delete Content Call

curl --location --request DELETE 'https://api.us.lifeomic.com/v1/content/<projectId>/content/<contentId>' \
--header 'LifeOmic-Account: <account-id>' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <api-key>'

Create a Course

Creating a course requires four major operations. The first is to create the content item. A content item is designated by the contentId. You can think of this as the name and concept of the course, such as might appear as an entry in a college catalog. The second operation is to create the files that make up the course material, such as audio, graphic, text, or video files. A file is designated by the fileId. When we have created both items, the third operation is to attach the files to the content. Then we have a course made up of a contentId with fileAttachments of fileIds. Our last step is to publish this course and move it out of the initial draft state.

Create Content

Make a POST https://api.us.lifeomic.com/v1/content/{{projectId}}/content call to create a content item. If an id is not supplied by the user, a unique id is assigned with the response. This id is the contentId you need for future operations.

The POST call requires body data in the JSON format. This table details the minimum data keys required to create a content item.

KeyValueMandatory
idcontentIdOptional
projectprojectIdRequired
displayNamecourse-nameRequired
typeeducation-component-typeRequired
slugdeveloper-supplied-slugRequired

For Postman, click the Body tab and select the raw option and JSON. Paste the JSON key and value string in the text box.

Postman

Example of Create Content Call

curl --location 'https://api.us.lifeomic.com/v1/content/<projectId>/content' \
--header 'LifeOmic-Account: <account-id>' \
--header 'Accept: application/json' \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '{
"project": "<projectId>",
"displayName": "<course-name>",
"type": "course",
"slug": "<developer-supplied-slug>"
}'

Response to Create Content Call

The response to the POST call contains the id key that contains the ContentId value. It also adds fields for file and content attachments.

{
"id": "8256efc4-116f-4063-bd6b-6d63b4ad8b56",
"project": "<projectId>",
"displayName": "Test Course",
"type": "course",
"slug": "1defb12c-daae-42f2-b13c-b9d010ef8c00",
"status": "draft",
"isDirty": true,
"lastModified": "2023-06-20T14:57:52.066Z",
"account": "<account-name>",
"fileAttachments": [],
"contentAttachments": []
}

Upload a File

After you obtain a contentId with the POST content call, you upload a file. Uploading files is a two call operation. The first call is a POST call for a response that contains a postform URL. The second call is a POST call to upload the file to the postform URL.

These operations are described below and also contained in the Bash Script for File Operations.

POST Call to Create a File

Make a POST https://api.us.lifeomic.com/v1/content/{{projectId}}/file call to create a new file in the content service. The POST call requires body data in the JSON format. If a file ID is not supplied by the user, a unique file ID is assigned with the response.

For Postman, click the Body tab and select the raw option and JSON. Paste the JSON key and value string in the text box.

KeyValueMandatory
namefile-nameRequired
projectproject-idRequired
contentTypemedia-typeOptional
idfile-idOptional

Example of Create a File POST Call

This example shows the JSON string after the data signifier for the body.


curl --location 'https://api.us.lifeomic.com/v1/content/<projectId>/file' \
--header 'LifeOmic-Account: <account-id>' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <api-key>' \
--header 'Content-Type: application/json' \
--data '{"project":"<project-id>","name":"test5.png"}'

Response to Create a File POST Call

The response to the POST call contains the fileId as id. The Amazon S3 URL is after the postForm key.

{
"id": "<fileId>",
"name": "test.json",
"contentType": "application/json",
"userId": "lifeomic-user@company.com",
"meta": {
"isDirectory": false,
"private": false
},
"postForm": {
"url": "https://<s3-url>",
"fields": {
"ContentType": "application/json",
"bucket": "<amazon-bucket>",
"X-Amz-Algorithm": "<amz-algorithm>",
"X-Amz-Credential": "<amz-credential>",
"X-Amz-Date": "20230621T133333Z",
"X-Amz-Security-Token": "<token-value>",
"key": "<account>/<project-id>/<file-id>/test.json",
"Policy": "<policy-value>",
"X-Amz-Signature": "<signature-value>"
}
}
}

POST Call to Upload File Content

Make the POST call that uploads the file data against the postForm url from the first POST response. The required Amazon authentication parameters are also contained in the response. You need to include the Amazon authentication parameters as form data in the body of the request. You also need to include the path to the file to be uploaded in the body request.

The postForm url expires in sixty seconds. To create the POST call within this time period, you may need to use the Bash Script for File Operations.

Example of Upload a File POST Call

The cURL example shows the path to upload the file.


curl --location 'https://<s3-url>' \
--form 'ContentType="image/png"' \
--form 'bucket="<s3-bucket-name>"' \
--form 'X-Amz-Algorithm="AWS4-HMAC-SHA256"' \
--form 'X-Amz-Credential="<amz-credential>"' \
--form 'X-Amz-Date="20230622T151420Z"' \
--form 'X-Amz-Security-Token="<amz-security-token>"' \
--form 'key="<file-key>"' \
--form 'Policy="<policy-id>"' \
--form 'X-Amz-Signature="<amz-signature>"' \
--form 'file=@"/Users/johnsmith/Desktop/test5.png"'

Response to a Upload a File POST Call

A successful upload results in a 200 (OK) response message. You can also confirm the file is stored in the LifeOmic Platform with a GET Content File call.

Example of GET Content File Call

The GET content file call response contains the fileId.


curl --location 'https://api.us.lifeomic.com/v1/content/<projectId>/file' \
--header 'LifeOmic-Account: <account-id>' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <api-key>'

Attach a File to Content

After creating content and creating and uploading a file, you attach the file to the course. Attach a file to a course with the PUT https://api.us.lifeomic.com/v1/content/{{projectId}}/content/{{contentId}}/file-attachment/{{fileId}} call.

You will need the contentId from the content you created and the fileId from the file you uploaded. Use these two GET calls to find that information:

  • https://api.us.lifeomic.com/v1/content/{{projectId}}/content
  • https://api.us.lifeomic.com/v1/content/{{projectId}}/file

Example of Attach a File to Content PUT Call


curl --location --request PUT ''https://api.us.lifeomic.com/v1/content/<projectId>/content/<contentId>/file-attachment/<fileId>' \
--header 'LifeOmic-Account: <account-id>' \
--header 'Accept: application/json' \
--header 'Authorization: <api-key>'

Response to Attach a File to Content PUT Call

A successful attachment results in a 201 (Created) response message. You can also make a GET https://api.us.lifeomic.com/v1/content/<projectId>/content/<contentId> call and confirm the file is listed under fileAttachments in the response.

Access Public Content

Files put into content service are publicly accessible, by default. Files are accessible at: https://content.<env>.lifeomic.com/<account>/<projectId>/<fileId>/key/to/file.

You can find the file URL paired with the url key under fileAttachments in the response to a GET https://api.us.lifeomic.com/v1/content/<projectId>/content/<contentId> call.

Publish Content

Content is created with a default status of draft. You promote content from draft state to publish state with the POST https://api.us.lifeomic.com/v1/content/{{projectId}}/content/{{contentId}}/publish call.

You can demote from the publish state to the draft state with the POST https://api.us.lifeomic.com/v1/content/{{projectId}}/content/{{contentId}}/draft call.

You can find the current status of content in the response to a GET https://api.us.lifeomic.com/v1/content/{{projectId}}/content call.

Example of Publish Content Post Call

This cURL example uses the path parameter publish.


curl --location --request POST 'https://api.us.lifeomic.com/v1/content/<projectId>/content/<contentId>/publish' \
--header 'LifeOmic-Account: <account-id>' \
--header 'Accept: application/json' \
--header 'Authorization: <api-key>'

Response to Publish Content Post Call

The response shows the status change to published.

{
"id": "contentId",
"project": "projectId",
"displayName": "Test Course",
"type": "course",
"fields": {
"description": {
"value": "Test course description"
}
},
"slug": "1defb12c-daae-42f2-b13c-b9d010ef8c99",
"status": "published",
"isDirty": false,
"version": 1687448761669,
"lastModified": "2023-06-20T14:29:54.662Z",
"publishDate": "2023-06-22T15:46:01.669Z",
"account": "account-name"
}

Further Information

You have completed the basic operations for the content service. For additional information, see the Content Service section of the API Reference Information. You can see the service used with the LifeOmic Platform UI in the Programs feature. You can also Contact LifeOmic for more information on advanced operations.

Bash Script for File Operations

This script makes the POST call to Create a File, POST call to Upload File Content, and a GET call to display the files in the project.

#!/bin/bash

IP=$(curl --location 'https://api.us.lifeomic.com/v1/content/<project-id>/file' \
--header 'LifeOmic-Account: lifeomic' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <api-key>' \
--header 'Content-Type: application/json' \
--data '{"project":"<project-id>","name":"<filename.format>","contentType":"<content-type/format>","displayName": "<filename.format>"}')

# assign the value ContentType to a variable and print it
ContentType=$(echo $IP | jq -r '.postForm.fields.ContentType')
bucket=$(echo $IP | jq -r '.postForm.fields.bucket')
X_Amz_Algorithm=$(echo $IP | jq -r '.postForm.fields."X-Amz-Algorithm"')
X_Amz_Credential=$(echo $IP | jq -r '.postForm.fields."X-Amz-Credential"')
X_Amz_Date=$(echo $IP | jq -r '.postForm.fields."X-Amz-Date"')
X_Amz_Security_Token=$(echo $IP | jq -r '.postForm.fields."X-Amz-Security-Token"')
key=$(echo $IP | jq -r '.postForm.fields.key')
Policy=$(echo $IP | jq -r '.postForm.fields.Policy')
X_Amz_Signature=$(echo $IP | jq -r '.postForm.fields."X-Amz-Signature"')

IP=$(curl --location 'https://s3.us-east-1.amazonaws.com/lifeomic-us-content-service-files' \
--form 'ContentType="'$ContentType'"' \
--form 'bucket="'$bucket'"' \
--form 'X-Amz-Algorithm="'$X_Amz_Algorithm'"' \
--form 'X-Amz-Credential="'$X_Amz_Credential'"' \
--form 'X-Amz-Date="'$X_Amz_Date'"' \
--form 'X-Amz-Security-Token="'$X_Amz_Security_Token'"' \
--form 'key="'$key'"' \
--form 'Policy="'$Policy'"' \
--form 'X-Amz-Signature="'$X_Amz_Signature'"' \
--form 'file=@"/home/jeffbeard/Desktop/test6.png"')

IP=$(curl --location 'https://api.us.lifeomic.com/v1/content/<project-id>/file' \
--header 'LifeOmic-Account: <account-name>' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <api-key>' \
--header 'Content-Type: application/json')

echo $IP | jq .