Content Workflows API Documentation
Content Workflows
List all content workflows
Parameters
No parameters.
Returns
Returns a list of content workflows for the user.
Request
GET /api/v2/content_workflows
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"data": [
{
"object": "keyword_brief",
"id": 1,
"keywords": "tatooine",
"country_code": "US",
"lang_code": "en",
"project_id": 1,
"status": "unstarted",
"created_at": "2025-07-17T20:02:47.565Z",
"started_at": null,
"completed_at": null,
"content_difficulty": null,
"average_word_count": null,
"search_volume": null,
"cpc": null
},
{
"object": "keyword_brief",
"id": 2,
"keywords": "moisture farming",
"country_code": "US",
"lang_code": "en",
"project_id": 1,
"status": "unstarted",
"created_at": "2026-05-17T20:02:47.565Z",
"started_at": null,
"completed_at": null,
"content_difficulty": null,
"average_word_count": null,
"search_volume": null,
"cpc": null
}
]
}
Create a content workflow
Parameters
- project_id
required - The ID of an existing project for the user.
- keywords
required - The keyword phrase for the content workflow.
- country_code
optional, default is project default country code - Two-letter country code for content workflow, in uppercase.
- lang_code
optional, default is project default language code - Language code for content workflow, in lowercase.
Returns
Returns the content workflow if it was created successfully.
Request
POST /api/v2/content_workflows
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows \
-X POST \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json' \
-d '{"project_id":272,"keywords":"tatooine","country_code":"US","lang_code":"en"}'
fetch('https://app.contentharmony.com/api/v2/content_workflows', {
method: 'POST',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
body: JSON.stringify({"project_id":272,"keywords":"tatooine","country_code":"US","lang_code":"en"})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
data = {"project_id":272,"keywords":"tatooine","country_code":"US","lang_code":"en"}
response = requests.post(url, auth=auth, headers=headers, json=data)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows')
request = Net::HTTP::Post.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
request.body = {"project_id":272,"keywords":"tatooine","country_code":"US","lang_code":"en"}
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "keyword_brief",
"id": 1,
"keywords": "tatooine",
"country_code": "US",
"lang_code": "en",
"project_id": 1,
"status": "unstarted",
"created_at": "2025-07-17T20:02:47.569Z",
"started_at": null,
"completed_at": null,
"content_difficulty": null,
"average_word_count": null,
"search_volume": null,
"cpc": null
}
Retrieve a content workflow
Parameters
No parameters.
Returns
Returns a content workflow if a valid ID was provided. The response includes:
- Basic fields - id, keywords, country_code, lang_code, project_id, status, timestamps
- General metrics (only for completed workflows with search_intent_report):
content_difficulty- Average content score of top-ranking pages (0-100)average_word_count- Average word count of top-ranking pagessearch_volume- Monthly search volume for the keywordcpc- Cost per click in USD
- links - Array of sharing links for this workflow
- resources (only for completed workflows) - URLs to detailed report sections:
intent- Search intent analysis endpointtopics- Topics analysis endpointrelated_keywords- Related keywords endpointoutline- Outline/headings analysis endpointquestions- Questions analysis endpointreferenced_links- Referenced links endpointinternal_links- Internal links endpointgov_edu_sources- Government and educational sources endpointnews_sources- News sources endpointsuggested_images- AI-suggested images endpointgoogle_image_results- Image search results endpointcompetitor_images- Images from competing pages endpointshopping_images- Shopping product images endpointvideos- Video search results endpointcompetitors- Competing URLs endpoint
Note: General metrics will be null for incomplete workflows or workflows without a search_intent_report.
Request
GET /api/v2/content_workflows/1
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1 \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "keyword_brief",
"id": 1,
"keywords": "tatooine",
"country_code": "US",
"lang_code": "en",
"project_id": 1,
"status": "completed",
"created_at": "2025-07-17T20:02:47.573Z",
"started_at": null,
"completed_at": "2026-07-16T20:02:47.573Z",
"content_difficulty": null,
"average_word_count": null,
"search_volume": null,
"cpc": null,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/brief"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/brief"
}
],
"resources": {
"intent": "https://app.contentharmony.com/api/v2/content_workflows/1/intent",
"topics": "https://app.contentharmony.com/api/v2/content_workflows/1/topics",
"related_keywords": "https://app.contentharmony.com/api/v2/content_workflows/1/related_keywords",
"outline": "https://app.contentharmony.com/api/v2/content_workflows/1/outline",
"questions": "https://app.contentharmony.com/api/v2/content_workflows/1/questions",
"referenced_links": "https://app.contentharmony.com/api/v2/content_workflows/1/referenced_links",
"internal_links": "https://app.contentharmony.com/api/v2/content_workflows/1/internal_links",
"gov_edu_sources": "https://app.contentharmony.com/api/v2/content_workflows/1/gov_edu_sources",
"news_sources": "https://app.contentharmony.com/api/v2/content_workflows/1/news_sources",
"suggested_images": "https://app.contentharmony.com/api/v2/content_workflows/1/suggested_images",
"google_image_results": "https://app.contentharmony.com/api/v2/content_workflows/1/google_image_results",
"competitor_images": "https://app.contentharmony.com/api/v2/content_workflows/1/competitor_images",
"shopping_images": "https://app.contentharmony.com/api/v2/content_workflows/1/shopping_images",
"videos": "https://app.contentharmony.com/api/v2/content_workflows/1/videos",
"competitors": "https://app.contentharmony.com/api/v2/content_workflows/1/competitors"
}
}
Retrieve intent analysis for a content workflow
Parameters
No parameters.
Returns
Returns the search intent analysis for this content workflow. The response includes:
- primary_intent - The dominant intent type identified (e.g., "Informational", "Transactional", "Research")
- intent_scores - Intent scores on a 0-3 scale for each intent category
- serp_features - Array of SERP feature names present (e.g., "people_also_ask", "knowledge_panel", "video_results", "ads")
- featured_content - Special SERP elements including:
ai_overview- Google AI Overview contentanswer_box- Featured snippet / answer boxknowledge_graph- Knowledge panel data
- keyword_trends - Google Trends URLs:
timeseries_url- URL for time series trend datageo_map_url- URL for geographic trend data
- freshness - SERP freshness data including:
average_age- Average age in days of dates shown in SERP resultstimeline- Desktop and mobile timeline data (newest, median, oldest dates)age_brackets- Desktop and mobile age distribution (Past Day, Past Week, Past Month, Past Year, Years Ago, No Date)
- metadata - Contains tab-specific sharing
links
Note: This endpoint is available for content workflows in any status. If the search intent report hasn't been calculated yet, fields will be null.
Request
GET /api/v2/content_workflows/1/intent
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/intent \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/intent', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/intent'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/intent')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "intent_report",
"primary_intent": "Research",
"intent_scores": {
"Research": 3,
"Transactional": 2,
"Opinion": 1,
"Fresh / News": 1,
"Answers": 1,
"Video": 1,
"Visual": 1,
"Brand / Entity": 1,
"Local": 0
},
"serp_features": [
"people_also_ask",
"featured_snippet",
"video_results",
"ads"
],
"featured_content": {
"ai_overview": null,
"answer_box": null,
"knowledge_graph": null
},
"keyword_trends": {
"timeseries_url": "https://trends.google.com/trends/explore?date=2004-01-01%202026-07-17&geo=US&q=tatooine",
"geo_map_url": "https://trends.google.com/trends/explore?date=2004-01-01%202026-07-17&geo=US&q=tatooine"
},
"freshness": {
"average_age": null,
"timeline": {
"desktop": {
"newest_date": null,
"median_date": null,
"oldest_date": null
},
"mobile": {
"newest_date": null,
"median_date": null,
"oldest_date": null
}
}
},
"metadata": {
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/intent"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/intent"
}
]
}
}
List topics for a content workflow
Parameters
No parameters.
Returns
Returns a list of topics (IBM keywords) analyzed for this content workflow. The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks(points to /topic tab where both topics and related keywords are displayed) - topics - Array of topics with:
phrase- The topic phrasedocuments_count- Number of top-ranking pages mentioning this topictotal_occurrences_count- Total mentions across all pagespriority- Importance score (0-100, based on percentage of pages containing topic)variants- Alternative phrasings of the topichighlighted- Whether topic was highlighted by userignored- Whether topic was ignored by user
Note: Topics are ordered by documents_count (descending), then total_occurrences_count (descending).
Request
GET /api/v2/content_workflows/1/topics
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/topics \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/topics', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/topics'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/topics')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/topic"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/topic"
}
]
},
"topics": [
{
"object": "topic",
"id": 1,
"phrase": "tusken raiders",
"documents_count": 8,
"total_occurrences_count": 42,
"priority": 85,
"variants": [
"tusken raider",
"sand people"
],
"highlighted": true,
"ignored": false,
"content_grader_uses": 0
},
{
"object": "topic",
"id": 2,
"phrase": "moisture farming",
"documents_count": 6,
"total_occurrences_count": 28,
"priority": 65,
"variants": [
"moisture farm",
"water farming"
],
"highlighted": false,
"ignored": false,
"content_grader_uses": 0
}
]
}
List related keywords for a content workflow
Parameters
No parameters.
Returns
Returns a list of related search keywords from Google for this content workflow. These are the "related searches" that appear at the bottom of Google search results. The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks(points to /topic tab where both topics and related keywords are displayed) - related_keywords - Array of related searches with:
phrase- The related search phraseposition- Order in which Google displays them (0-indexed)highlighted- Whether keyword was highlighted by user
Note: Related keywords are ordered by position (ascending), matching the order Google displays them.
Request
GET /api/v2/content_workflows/1/related_keywords
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/related_keywords \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/related_keywords', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/related_keywords'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/related_keywords')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/topic"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/topic"
}
]
},
"related_keywords": [
{
"object": "related_keyword",
"id": 1,
"phrase": "tatooine sunset",
"position": 0,
"highlighted": true
},
{
"object": "related_keyword",
"id": 2,
"phrase": "tatooine map",
"position": 1,
"highlighted": false
}
]
}
List outline headings for a content workflow
Parameters
No parameters.
Returns
Returns outline headings grouped by source for this content workflow. Headings come from two types of sources:
- AISuggestion - AI-generated heading suggestions for the content
- Url - Headings extracted from competitor pages that rank for this keyword
The response includes:
- metadata - Contains
total_count,highlighted_count,ai_suggestions_count,competitor_urls_count, and sharinglinks - heading_sources - Array of sources, each containing:
source_type- Either "AISuggestion" or "Url"source_id- ID of the sourcesource_url- URL of the competitor page (only for Url sources)total_headings- Number of headings from this sourcehighlighted_headings- Number of highlighted headings from this sourceheadings- Array of heading objects with:heading_text- The heading contentheading_type- Type (h1, h2, h3, h4, h5, h6, li)source_position- Order in which heading appears on the source page (0-indexed)highlighted- Whether heading was highlighted by user
Note: AI suggestion sources appear first, followed by URL sources. Headings within each source are ordered by source_position (ascending), matching the order they appear on the original page.
Request
GET /api/v2/content_workflows/1/outline
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/outline \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/outline', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/outline'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/outline')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 4,
"highlighted_count": 1,
"ai_suggestions_count": 1,
"competitor_urls_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/outline"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/outline"
}
]
},
"heading_sources": [
{
"object": "heading_source",
"source_type": "AISuggestion",
"source_id": 1,
"total_headings": 2,
"highlighted_headings": 1,
"headings": [
{
"object": "heading",
"id": 1,
"heading_text": "Geography and Climate",
"heading_type": "h2",
"source_position": 0,
"highlighted": true
},
{
"object": "heading",
"id": 2,
"heading_text": "Notable Inhabitants",
"heading_type": "h3",
"source_position": 1,
"highlighted": false
}
]
},
{
"object": "heading_source",
"source_type": "Url",
"source_id": 1,
"source_url": "https://en.wikipedia.org/wiki/Tatooine",
"total_headings": 2,
"highlighted_headings": 0,
"headings": [
{
"object": "heading",
"id": 3,
"heading_text": "Tatooine in Star Wars",
"heading_type": "h1",
"source_position": 0,
"highlighted": false
},
{
"object": "heading",
"id": 4,
"heading_text": "Major Locations and Settlements",
"heading_type": "h2",
"source_position": 1,
"highlighted": false
}
]
}
]
}
List questions for a content workflow
Parameters
No parameters.
Returns
Returns questions for this content workflow ordered by category and source position. Questions come from multiple source types:
- AI Suggestion - AI-generated questions about the topic
- Google PAA - People Also Ask questions from Google search results
- Quora - Questions from Quora related to the topic
- Stack Exchange - Questions from Stack Exchange sites
- Reddit - Questions from Reddit discussions
- Yahoo! Answers - Questions from Yahoo! Answers (deprecated)
The response includes:
- metadata - Contains
total_count,highlighted_count,by_categorybreakdown, and sharinglinks - questions - Array of question objects, each containing:
question_text- The actual question textcategory- Category symbol (ai_suggestion, desktop, quora, stack_exchange, reddit, yahoo_answers)category_name- Display name for the categorysource_position- Order within the source (0-indexed)snippet- Answer snippet or description (optional)title- Page/article title (optional)displayed_link- Display URL (optional)url- Full URL (optional, only for questions with associated URL)highlighted- Whether question was highlighted by user
Note: Questions are ordered by category (Google PAA first, AI Suggestion second, then others), then by source_position within each category.
Request
GET /api/v2/content_workflows/1/questions
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/questions \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/questions', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/questions'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/questions')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 3,
"highlighted_count": 1,
"by_category": {
"ai_suggestions": 1,
"google_paa": 2,
"quora": 0,
"stack_exchange": 0,
"reddit": 0,
"yahoo_answers": 0
},
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/questions"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/questions"
}
]
},
"questions": [
{
"object": "question",
"id": 1,
"question_text": "Where is Tatooine in real life?",
"category": "ai_suggestion",
"category_name": "AI Suggestion",
"source_position": 0,
"snippet": null,
"title": null,
"displayed_link": null,
"highlighted": true
},
{
"object": "question",
"id": 2,
"question_text": "Why is Tatooine included in so many Star Wars plots?",
"category": "desktop",
"category_name": "Google PAA",
"source_position": 0,
"snippet": "Tatooine filming locations include Tunisia in North Africa...",
"title": "Tatooine Filming Locations",
"displayed_link": "en.wikipedia.org/wiki/Tatooine",
"url": "https://en.wikipedia.org/wiki/Tatooine",
"highlighted": false
},
{
"object": "question",
"id": 3,
"question_text": "What's so special about Tatooine?",
"category": "desktop",
"category_name": "Google PAA",
"source_position": 1,
"snippet": "It appeared twice in the original trilogy because it was Luke's home planet...",
"title": "Understanding Tatooine's Importance",
"displayed_link": "starwars.fandom.com/wiki/Tatooine",
"url": "https://en.wikipedia.org/wiki/Tatooine",
"highlighted": false
}
]
}
List competitors for a content workflow
Parameters
No parameters.
Returns
Returns a list of competitor pages analyzed for this content workflow. The response includes:
- metadata - Contains
total_count,highlighted_count, and tab-specific sharinglinks - data - Array of competitors with ranking position, traffic estimates, keyword data, and highlighted status
Note: This endpoint is available for content workflows in any status. The URL will be included in the resources object when retrieving a completed content workflow.
Request
GET /api/v2/content_workflows/1/competitors
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/competitors \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/competitors', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/competitors'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/competitors')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/competitors"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/competitors"
}
]
},
"competitors": [
{
"object": "competitor",
"id": 1,
"position": 1,
"title": "Tatooine - Wikipedia",
"description": "Desert planet in the Star Wars galaxy",
"thumbnail": null,
"url": "https://en.wikipedia.org/wiki/Tatooine",
"domain": "en.wikipedia.org",
"estimated_traffic": 5000,
"total_keywords": 150,
"top_keyword": "tatooine",
"top_keyword_position": 3,
"top_keyword_volume": 12000,
"highlighted": false
},
{
"object": "competitor",
"id": 2,
"position": 2,
"title": "Tatooine | Wookieepedia",
"description": "Complete guide to Tatooine's history and locations",
"thumbnail": null,
"url": "https://starwars.fandom.com/wiki/Tatooine",
"domain": "en.wikipedia.org",
"estimated_traffic": 3200,
"total_keywords": 98,
"top_keyword": "tatooine locations",
"top_keyword_position": 5,
"top_keyword_volume": 8500,
"highlighted": true
}
]
}
List referenced links for a content workflow
Parameters
No parameters.
Returns
Returns external authoritative links that appear across multiple top-ranking pages for this keyword. These are links commonly cited as references or resources by content that ranks well for the topic.
The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks - referenced_links - Array of link objects ordered by
total_occurrences_count(descending), each containing:id- Unique identifierurl- The referenced URLtotal_occurrences_count- Number of times this link appears across top-ranking contenthighlighted- Whether link was highlighted by user
Note: Links are ordered by total_occurrences_count (descending), showing the most commonly referenced sources first.
Request
GET /api/v2/content_workflows/1/referenced_links
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/referenced_links \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/referenced_links', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/referenced_links'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/referenced_links')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/sources"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/sources"
}
]
},
"referenced_links": [
{
"object": "referenced_link",
"id": 1,
"url": "https://starwars.fandom.com/wiki/Tusken_Raiders",
"total_occurrences_count": 15,
"highlighted": true
},
{
"object": "referenced_link",
"id": 2,
"url": "https://starwars.fandom.com/wiki/Moisture_farming",
"total_occurrences_count": 8,
"highlighted": false
}
]
}
List internal links for a content workflow
Parameters
No parameters.
Returns
Returns internal pages from your own domain that rank for this keyword. This helps identify which existing content on your site is already performing well for the topic.
The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks - internal_links - Array of internal page objects ordered by
source_position, each containing:id- Unique identifierurl- The page URLtitle- Page title from search resultssnippet- Meta description or snippet textdisplayed_link- Display URL from search resultssource_position- Ranking position in search resultssource_name- Source identifier (optional)date- Publication date (optional)thumbnail- Thumbnail image URL (optional)highlighted- Whether page was highlighted by user
Note: Only available if a project domain is configured. Internal links are ordered by source_position (ranking).
Request
GET /api/v2/content_workflows/1/internal_links
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/internal_links \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/internal_links', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/internal_links'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/internal_links')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/sources"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/sources"
}
]
},
"internal_links": [
{
"object": "source",
"id": 1,
"url": "https://mysite.com/tatooine-guide",
"title": "Complete Guide to Tatooine",
"snippet": "Everything you need to know about the desert planet...",
"displayed_link": "mysite.com/tatooine-guide",
"source_position": 1,
"source_name": null,
"date": null,
"thumbnail": null,
"highlighted": false
},
{
"object": "source",
"id": 2,
"url": "https://mysite.com/outer-rim-planets",
"title": "Outer Rim Planets: Tatooine",
"snippet": "Exploring the most iconic desert world in Star Wars...",
"displayed_link": "mysite.com/outer-rim-planets",
"source_position": 2,
"source_name": null,
"date": null,
"thumbnail": null,
"highlighted": true
}
]
}
List government and educational sources for a content workflow
Parameters
No parameters.
Returns
Returns authoritative content from .gov and .edu domains related to this keyword. These sources are often highly trusted and can provide credible references for your content.
The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks - gov_edu_sources - Array of source objects ordered by
source_position, each containing:id- Unique identifierurl- The source URLtitle- Page title from search resultssnippet- Description or excerpt textdisplayed_link- Display URL from search resultssource_position- Order in search resultssource_name- Source identifier (optional)date- Publication date (optional)thumbnail- Thumbnail image URL (optional)highlighted- Whether source was highlighted by user
Note: Sources are ordered by source_position from the search results.
Request
GET /api/v2/content_workflows/1/gov_edu_sources
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/gov_edu_sources \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/gov_edu_sources', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/gov_edu_sources'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/gov_edu_sources')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/sources"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/sources"
}
]
},
"gov_edu_sources": [
{
"object": "source",
"id": 1,
"url": "https://climate.nasa.gov/effects",
"title": "The Effects of Climate Change - NASA",
"snippet": "Scientific evidence shows climate change is affecting...",
"displayed_link": "climate.nasa.gov/effects",
"source_position": 1,
"source_name": null,
"date": null,
"thumbnail": null,
"highlighted": true
},
{
"object": "source",
"id": 2,
"url": "https://university.edu/climate-research",
"title": "Climate Change Research - University Study",
"snippet": "Academic research on climate impacts and projections...",
"displayed_link": "university.edu/climate-research",
"source_position": 2,
"source_name": null,
"date": null,
"thumbnail": null,
"highlighted": false
}
]
}
List news sources for a content workflow
Parameters
No parameters.
Returns
Returns recent news articles and coverage related to this keyword. News sources can help identify trending topics, breaking developments, and timely content opportunities.
The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks - news_sources - Array of news article objects ordered by
source_position, each containing:id- Unique identifierurl- The article URLtitle- Article headlinesnippet- Article excerpt or descriptiondisplayed_link- Display URL from search resultssource_position- Order in news resultssource_name- News outlet name (e.g., "CNN", "BBC News")date- Publication date/time (e.g., "2 hours ago")thumbnail- Article thumbnail image URL (optional)highlighted- Whether article was highlighted by user
Note: News sources are ordered by source_position (relevance/recency) from Google News results.
Request
GET /api/v2/content_workflows/1/news_sources
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/news_sources \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/news_sources', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/news_sources'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/news_sources')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/sources"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/sources"
}
]
},
"news_sources": [
{
"object": "source",
"id": 1,
"url": "https://news.com/ev-breakthrough",
"title": "Major Breakthrough in Electric Vehicle Technology",
"snippet": "Scientists announce new battery technology that could triple EV range...",
"displayed_link": "news.com",
"source_position": 1,
"source_name": "Tech News Daily",
"date": "2 hours ago",
"thumbnail": "https://news.com/images/ev-thumbnail.jpg",
"highlighted": false
},
{
"object": "source",
"id": 2,
"url": "https://news.com/battery-technology",
"title": "New Battery Tech Could Transform Electric Vehicles",
"snippet": "Industry experts say the innovation marks a turning point...",
"displayed_link": "news.com",
"source_position": 2,
"source_name": "Auto Industry Report",
"date": "5 hours ago",
"thumbnail": null,
"highlighted": true
}
]
}
List AI-suggested images for a content workflow
Parameters
No parameters.
Returns
Returns AI-generated suggestions for images that would be effective for this keyword. These are text-only recommendations (title and description) suggesting types of images to create or source.
The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks - suggested_images - Array of AI suggestion objects, each containing:
id- Unique identifiertitle- Brief title of the image suggestiondescription- Detailed description of the suggested imagehighlighted- Whether suggestion was highlighted by user
Note: These are text-based suggestions, not actual images. Use them as guidance for creating or sourcing visual content.
Request
GET /api/v2/content_workflows/1/suggested_images
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/suggested_images \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/suggested_images', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/suggested_images'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/suggested_images')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/images"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/images"
}
]
},
"suggested_images": [
{
"object": "suggested_image",
"id": 1,
"title": "Tatooine Desert Landscape",
"description": "Show the iconic twin suns setting over Tatooine's vast desert dunes to demonstrate the planet's harsh environment and iconic scenery.",
"highlighted": false
},
{
"object": "suggested_image",
"id": 2,
"title": "Mos Eisley Spaceport Aerial View",
"description": "Display the famous Mos Eisley spaceport from above, highlighting the distinctive architecture and bustling activity of this notorious trading hub.",
"highlighted": true
}
]
}
List image search results for a content workflow
Parameters
No parameters.
Returns
Returns images from image search results for this keyword. These are actual images that rank in image search for the target keyword.
The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks - google_image_results - Array of image result objects ordered by
source_position, each containing:id- Unique identifierurl- The source page URL containing the imagetitle- Image title from search resultssnippet- Description or contextdisplayed_link- Display URL from search resultssource_position- Ranking position in image resultssource_name- Source website name (optional)date- Publication date (optional)thumbnail- Thumbnail image URLimage- Full-size image URLhighlighted- Whether image was highlighted by user
Note: Results are ordered by source_position (ranking in image search results).
Request
GET /api/v2/content_workflows/1/google_image_results
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/google_image_results \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/google_image_results', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/google_image_results'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/google_image_results')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 2,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/images"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/images"
}
]
},
"google_image_results": [
{
"object": "image_result",
"id": 1,
"url": "https://en.wikipedia.org/wiki/Tatooine",
"title": "Tatooine Desert Landscape",
"snippet": "The harsh twin-sun desert world of Tatooine",
"displayed_link": "example.com",
"source_position": 1,
"source_name": null,
"date": null,
"thumbnail": "https://example.com/images/tatooine-thumb.jpg",
"image": "https://example.com/images/tatooine-full.jpg",
"highlighted": true
},
{
"object": "image_result",
"id": 2,
"url": "https://starwars.fandom.com/wiki/Tatooine/Legends",
"title": "Twin Suns of Tatooine",
"snippet": "Iconic binary sunset on the desert planet",
"displayed_link": "example.com",
"source_position": 2,
"source_name": null,
"date": null,
"thumbnail": "https://example.com/images/twin-suns-thumb.jpg",
"image": "https://example.com/images/twin-suns-full.jpg",
"highlighted": false
}
]
}
List images from competing pages
Parameters
No parameters.
Returns
Returns actual images found on top-ranking competitor pages for this keyword. This shows you what visual content is being used by pages that rank well.
The response includes:
- metadata - Contains sharing
links - competitors - Array of competitor objects ordered by ranking position, each containing:
position- Ranking position in search resultsurl- The competitor page URLtitle- Page title from search resultsimages- Array of image URLs found on this page (up to 24 images)- Absolute URLs (http/https) are returned as-is
- Relative URLs are converted to absolute using the page's domain
- Invalid images (data URIs, SVGs, broken paths) are filtered out
Note: Images are extracted from successfully crawled competitor pages. Empty arrays indicate no images were found or the page could not be crawled.
Request
GET /api/v2/content_workflows/1/competitor_images
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/competitor_images \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/competitor_images', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/competitor_images'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/competitor_images')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/images"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/images"
}
]
},
"competitors": [
{
"object": "competitor",
"position": 1,
"url": "https://competitor1.com/tatooine-guide",
"title": "Complete Guide to Tatooine: Everything You Need to Know",
"images": []
},
{
"object": "competitor",
"position": 2,
"url": "https://competitor2.com/desert-planet-living",
"title": "Living on Desert Planets: A Comprehensive Guide",
"images": []
}
]
}
List shopping product images for a content workflow
Parameters
No parameters.
Returns
Returns product images from Google Shopping results for this keyword. These show actual products being sold that match the search term.
The response includes:
- metadata - Contains sharing
links - shopping_images - Array of shopping product objects (up to 8 results), each containing:
thumbnail- Product image thumbnail URLprice- Product price as displayedlink- Link to product pagesource- Merchant or store nametitle- Product title
Note: Shopping images are only available when Google Shopping results exist for the keyword. Returns empty array if no shopping results are found.
Request
GET /api/v2/content_workflows/1/shopping_images
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/shopping_images \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/shopping_images', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/shopping_images'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/shopping_images')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/images"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/images"
}
]
},
"shopping_images": [
{
"object": "shopping_image",
"thumbnail": "https://shopping.example.com/images/tatooine-poster-thumb.jpg",
"price": "$29.99",
"link": "https://shopping.example.com/products/tatooine-poster",
"source": "Star Wars Shop",
"title": "Tatooine Landscape Poster - 24x36"
},
{
"object": "shopping_image",
"thumbnail": "https://shopping.example.com/images/tatooine-map-thumb.jpg",
"price": "$19.99",
"link": "https://shopping.example.com/products/tatooine-map",
"source": "Galactic Collectibles",
"title": "Detailed Map of Tatooine"
}
]
}
List videos for a content workflow
Parameters
No parameters.
Returns
Returns video search results from Google Video Search for this keyword. These are videos that rank for the target keyword.
The response includes:
- metadata - Contains
total_count,highlighted_count, and sharinglinks - videos - Array of video objects ordered by ranking position, each containing:
id- Unique identifier for the video resulturl- Full URL to the videotitle- Video title from search resultssnippet- Video description snippetdisplayed_link- Domain displayed in search resultssource_position- Ranking position in video search resultssource_name- Video platform name (e.g., "YouTube", "Vimeo")date- Publication or upload date if availablerich_snippet- Additional metadata (duration, views, etc.)highlighted- Boolean indicating if video was highlighted
Note: Videos are only available when Google Video Search results exist for the keyword. Returns empty array if no video results are found.
Request
GET /api/v2/content_workflows/1/videos
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/videos \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/videos', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/videos'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/videos')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "list",
"metadata": {
"total_count": 3,
"highlighted_count": 1,
"links": [
{
"object": "link",
"id": null,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/sharediscussion01/videos"
},
{
"object": "link",
"id": null,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/sharereadonly0001/videos"
}
]
},
"videos": [
{
"object": "video",
"id": 1,
"url": "https://www.youtube.com/watch?v=abc123",
"title": "Complete History of Tatooine - YouTube",
"snippet": "Explore the complete history of Tatooine from its discovery to its role in the Skywalker saga",
"displayed_link": "youtube.com",
"source_position": 1,
"source_name": "YouTube",
"date": "Jan 15, 2024",
"rich_snippet": {
"top": {
"extensions": [
"12:15",
"2.3M views"
]
}
},
"highlighted": true
},
{
"object": "video",
"id": 2,
"url": "https://www.youtube.com/watch?v=def456",
"title": "Visiting Tatooine Filming Locations - YouTube",
"snippet": "Join us as we explore the real-world filming locations in Tunisia used for Tatooine scenes",
"displayed_link": "youtube.com",
"source_position": 2,
"source_name": "YouTube",
"date": "Feb 1, 2024",
"rich_snippet": {
"top": {
"extensions": [
"18:42",
"890K views"
]
}
},
"highlighted": false
},
{
"object": "video",
"id": 3,
"url": "https://vimeo.com/987654321",
"title": "Tatooine: A Geographic Analysis",
"snippet": "Analyzing the geography, climate, and settlements of Star Wars' most iconic desert planet",
"displayed_link": "vimeo.com",
"source_position": 3,
"source_name": "Vimeo",
"date": "Dec 20, 2023",
"rich_snippet": {
"top": {
"extensions": [
"15:30",
"450K views"
]
}
},
"highlighted": false
}
]
}
Get content brief for a content workflow
Parameters
No parameters.
Returns
Returns the editable content brief for this content workflow as HTML. The brief contains user-written or AI-generated content structured in a rich text format.
The HTML content is formatted for easy import into Google Docs, Microsoft Word, or other rich text editors.
- object - Always "brief"
- keyword_brief_id - ID of the associated content workflow
- id - Unique identifier for the brief (null if no brief exists)
- created_at - When the brief was first created (null if no brief exists)
- updated_at - When the brief was last modified (null if no brief exists)
- html_content - The brief content converted to HTML (null if no content)
- has_content - Boolean indicating whether the brief has any content
- message - Informational message when no brief exists
Note: Not all content workflows have associated content briefs. If no brief has been created yet, the endpoint will return null values with has_content: false.
The HTML content includes proper formatting for headings, paragraphs, lists, tables, code blocks, and other rich text elements. It also may include data from the keyword report if the user highlighted items like competitors, topics, or questions to include in their brief.
Request
GET /api/v2/content_workflows/1/brief
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/brief \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/brief', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/brief'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/brief')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "brief",
"keyword_brief_id": 1,
"id": 1,
"created_at": "2026-07-16T20:02:47.738Z",
"updated_at": "2026-07-17T19:02:47.738Z",
"html_content": "<h1>Complete Guide to Tatooine</h1><p>Tatooine, a remote desert planet in the Outer Rim, orbits twin suns and presents unique challenges for settlers and moisture farmers.</p><h2>Essential Survival Equipment</h2><ul><li>Moisture vaporators for water collection</li><li>Protection from twin suns heat</li><li>Sand filtration systems</li><li>Long-range communication devices</li></ul><h2>Top Moisture Farming Locations</h2><ol><li>Anchorhead region - Best moisture yield</li><li>Bestine Township - Safest from Tusken Raiders</li><li>Mos Eisley outskirts - Good trade access</li></ol>",
"has_content": true
}
Get content grader for a content workflow
Parameters
No parameters.
Returns
Returns the content grader data for a content workflow, including scoring metrics, draft content, and topic usage analysis. The content grader helps evaluate how well your content matches SEO best practices and competitor patterns.
This endpoint combines content scoring, the draft HTML, and topic analysis in a single response.
- object - Always "content_grader"
- keyword_brief_id - ID of the associated content workflow
- id - Unique identifier for the grader (null if no grader exists)
- metadata - Contains sharing
linkspointing to the /grader viewlinks- Array of sharing links withid,show_discussion, andurl(points to /grader tab)
- content_scoring - Object containing all scoring metrics:
content_score- Overall score (0-100)content_score_label- Label ("Poor", "Fair", "Good", "Great", "Greatest 💯")content_score_label_color- CSS class for score colorcurrent_word_count- Word count in the draftrecommended_word_count- Target word count based on competitorscurrent_readability- Flesch-Kincaid readability scorecurrent_readability_label- Grade level label (e.g., "8th Grade")recommended_readability- Target readability scorerecommended_terms_used- Number of recommended topics used in contentrecommended_terms_total- Total number of recommended topics
- content_draft - Object containing the draft content:
title- Title of the drafthtml_content- Full HTML content of the drafturl- Source URL if content was fetched from a competitor (null otherwise)has_content- Boolean indicating whether draft has content
- topics - Object containing topic analysis:
metadata- Containstotal_countandhighlighted_countitems- Array of topics (same structure as Get topics endpoint), with additionalcontent_grader_usesfield showing how many times each topic appears in the draft
Note: Not all content workflows have content graders. If no grader exists, the endpoint returns null values with empty scoring and draft objects.
The content score is calculated based on word count (10% weight) and topic usage (90% weight). A score of 71+ is considered "Great".
The content_grader_uses field in topics shows how many times each topic/keyword appears in the draft content, helping you identify which recommended topics you've covered.
Request
GET /api/v2/content_workflows/1/content_grader
- cURL
- JavaScript
- Python
- Ruby
curl https://app.contentharmony.com/api/v2/content_workflows/1/content_grader \
-X GET \
-u {{token}}:{{secret}} \
-H 'Content-Type: application/json'
fetch('https://app.contentharmony.com/api/v2/content_workflows/1/content_grader', {
method: 'GET',
headers: {
'Authorization': `Basic ${btoa('{{token}}:<span class="password-hidden" data-reveal-target="maskable">{{secret}}</span>')}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests
import json
url = 'https://app.contentharmony.com/api/v2/content_workflows/1/content_grader'
auth = ('{{token}}', '{{secret}}')
headers = {'Content-Type': 'application/json'}
response = requests.get(url, auth=auth, headers=headers)
print(response.json())
require 'net/http'
require 'json'
uri = URI('https://app.contentharmony.com/api/v2/content_workflows/1/content_grader')
request = Net::HTTP::Get.new(uri)
request.basic_auth('{{token}}', '{{secret}}')
request['Content-Type'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)
Response
{
"object": "content_grader",
"keyword_brief_id": 1,
"id": 1,
"created_at": "2026-07-10T20:02:47.744Z",
"updated_at": "2026-07-17T19:02:47.744Z",
"metadata": {
"links": [
{
"object": "link",
"id": 1,
"show_discussion": true,
"url": "https://app.contentharmony.com/l/abc123def456/grader"
},
{
"object": "link",
"id": 2,
"show_discussion": false,
"url": "https://app.contentharmony.com/l/xyz789ghi012/grader"
}
]
},
"content_scoring": {
"content_score": 78,
"content_score_label": "Great",
"content_score_label_color": "grader-great",
"current_word_count": 487,
"recommended_word_count": 650,
"current_readability": 68,
"current_readability_label": "8th Grade",
"recommended_readability": 70,
"recommended_terms_used": 7,
"recommended_terms_total": 10
},
"content_draft": {
"title": "Complete Guide to Living on Tatooine",
"html_content": "<h1>Complete Guide to Living on Tatooine</h1><p>Tatooine, the desert planet orbiting twin suns, presents unique challenges for settlers and moisture farmers. This comprehensive guide covers everything you need to know about surviving and thriving in this harsh environment.</p><h2>Essential Moisture Farming Equipment</h2><p>Moisture farming on Tatooine requires specialized vaporators that extract water from the atmosphere. Quality moisture farming equipment can mean the difference between prosperity and failure in the desert.</p><h2>Key Survival Tips</h2><ul><li>Maintain your vaporator maintenance schedule</li><li>Avoid traveling during the hottest hours</li><li>Watch for Tusken Raider activity</li><li>Keep sandcrawler parts in stock for repairs</li></ul><p>By following these guidelines, you can successfully establish your homestead on Tatooine.</p>",
"url": "https://example.com/tatooine-settlers-guide",
"has_content": true
},
"topics": {
"metadata": {
"total_count": 3,
"highlighted_count": 1
},
"items": [
{
"object": "topic",
"id": 1,
"phrase": "moisture farming equipment",
"documents_count": 8,
"total_occurrences_count": 42,
"priority": 85,
"variants": [
"moisture vaporators",
"water collection equipment"
],
"highlighted": true,
"ignored": false,
"content_grader_uses": 3
},
{
"object": "topic",
"id": 2,
"phrase": "vaporator maintenance",
"documents_count": 6,
"total_occurrences_count": 28,
"priority": 65,
"variants": [
"vaporator repair",
"equipment maintenance"
],
"highlighted": false,
"ignored": false,
"content_grader_uses": 2
},
{
"object": "topic",
"id": 3,
"phrase": "sandcrawler parts",
"documents_count": 5,
"total_occurrences_count": 18,
"priority": 50,
"variants": [
"jawa technology"
],
"highlighted": false,
"ignored": false,
"content_grader_uses": 0
}
]
}
}