Skip to main content

List Content

/marketing/content
List all content items for the current organization.
Response
The grounding. Every row carries the five fields that say who the piece is for, avatar_id, journey_id, journey_stage, before_after_grid_id and target_keyword (each present, null when unset; target_keyword reads settings.target_keyword on rows written before 2026-09-12), plus customer_avatar, customer_journey and before_after_grid as { id, name } or null. The same keys come back from every create, get and update below. Filters (Olympus). GET /api/olympus/marketing/content under an API key also filters on avatar_id, journey_id and before_after_grid_id (exact; a value that is not a UUID is a 400) and journey_stage (case-insensitive exact match on the stage name), beside status, content_type, category_id, tags and search. The content_list MCP tool takes the same. See Who this is for. Newest published first (Olympus). published_since (an ISO 8601 instant; only items whose published_at is at or after it; a value that is not a date is a 400) and sort (updated, the default, by updated_at descending, or published, by published_at descending) join the filters, so status=published&published_since=<a week ago>&sort=published is everything that went live since the last digest, newest first. The content_list tool and the List Marketing Content workflow node take the same two (the node also takes published_within_days).

Create Content

/marketing/content
Create a new content item.
Request Body
The grounding on create. avatar_id, journey_id and before_after_grid_id must name an avatar, a customer journey map and a before/after grid in this account (or be null); journey_stage is the stage name as the journey map spells it (up to 255 characters); target_keyword is up to 255 characters and lands on the target_keyword column, mirrored into settings.target_keyword. The Olympus POST /api/olympus/marketing/content and the content_create MCP tool take the same five.

Get Content

/marketing/content/{id}
Get a specific content item by ID. The item carries the five grounding fields and the customer_avatar, customer_journey and before_after_grid objects described under List Content; the Olympus GET /api/olympus/marketing/content/:contentId and content_get add url, url_source and scheduled_publish.

Update Content

/marketing/content/{id}
Update a content item. The body is the whole item as the editor sends it.
The grounding on update. avatar_id, journey_id, journey_stage, before_after_grid_id and target_keyword are accepted with the same rules as on create; null clears a field, and a key that is absent leaves its column alone. The three ids are checked against the account before any field is written, so a 400 invalid_reference writes nothing. settings is merged into the stored object, never replaced, so keys another writer added (linked tasks, the published route) survive an autosave; a keyword typed into settings.target_keyword wins over the echoed top-level target_keyword, and both end up equal. The Olympus PATCH /api/olympus/marketing/content/:contentId and the content_update MCP tool take the same five, with the top-level target_keyword winning there. The distribution plan. settings.distribution_plan is the piece’s channel plan, written at brief time and updated as derivatives are made: { owned_first: true, channels: [{ channel, format, status, scheduled_for?, link?, note? }], written_at }, where channel is email_digest, social, community, partner, outreach or paid, status is planned, drafted, scheduled, done or skipped, and link names the derivative (social_post:<id>, campaign:<id>, task:<id> or a URL). At most 12 rows. Because settings merges, a writer sends settings: { distribution_plan } alone and every sibling key survives; a malformed plan is read as no plan. The same key is accepted on create, on the Olympus routes and by content_create and content_update. See The distribution plan on the row. Scheduling. A scheduled_publish_at (ISO 8601, in the future) whose instant differs from the stored value is a schedule request and puts the item’s site entry on the CMS scheduler; the value the row already holds is ignored as an autosave echo, and null never cancels. Send cancel_scheduled_publish: true to cancel. deploy_target is production (default), staging, dev, none or publish (Webflow). See Scheduling and the Content Calendar.

Pre-Publish SEO Check

/marketing/content/{id}/seo-check
Run the on-page SEO check on the stored item. Requires marketing.content read.
Response
level is error or warn; field names the column to fix. ok is false only on errors; score is 100 minus 15 per error and 5 per warning. The same check is served under an Olympus API key at GET /api/olympus/marketing/content/{id}/seo-check, and POST /api/olympus/marketing/content/{id}/publish-to-site returns it as warnings and seo_check. Every check is listed on Pre-Publish SEO Check.

Content Calendar

/marketing/content/calendar
Everything scheduled, published, failed or recorded in a window. Query from and to (ISO 8601 or YYYY-MM-DD), each defaulting to 45 days from now; a window wider than 190 days is a 400.
Response
kind is scheduled, published, failed or recorded_only; executes is false only for recorded_only, a date stored on the item that nothing publishes. The cadence counts are account-wide. See Scheduling and the Content Calendar.
/olympus/marketing/content/site-links
Olympus API key. Every published post and page on one website project with its live URL, for internal linking. Query project_id (required, a website project UUID in the account) and limit (default and maximum 500).
Returns { data: [{ id, title, url, type, published_at, slug, source }], total, capped, project: { id, name, host }, posts: { listed, without_url }, pages: { listed }, notes }. type is post or page; source is content_item, page_list or crawl; notes explains anything missing. 400 project_id_required and 404 project_not_found are the errors. The Olympus content list and get also carry url (and get carries url_source) per item. See The Content Department.

Article Images

/marketing/content/{id}/images
Preview an article images run: no model call, no spend. Requires marketing.content read. The Olympus twin is GET /api/olympus/marketing/content/{id}/images under an API key.
Response
sections is every H2 in the body with whether an image already sits directly below it; candidates counts the ones a run could illustrate. allowance.remaining is null on an unlimited plan.
/marketing/content/{id}/images
Run the pipeline: plan a hero and one image per H2 that adds information, render them (hero first, then the sections with the hero and the brand references as reference images), register each in the Media Library, place each under its heading, and set the featured image. Requires marketing.content update; the account must be in good billing standing. The Olympus twin is POST /api/olympus/marketing/content/{id}/images. Runs up to 300 seconds.
Request Body (every field optional; an empty body runs the default)
Response
Every image is registered in the Media Library with its alt text, prompt and model under the tags content_image and content:<item id>; an asset_id of null means the image is hosted and placed but the library row could not be written. warnings names a heading that already had an image (left alone), a render that failed (its generation refunded) and, when the allowance ran out part-way, the images that were not made. See Images for the piece.

Brand Image Profile

/olympus/marketing/brand/image-profile
Olympus API key. The account’s brand image profile exactly as every branded image generation sends it. Read-only. Query project_id (optional website project UUID; that project’s own guide wins over the account-level guide). The brand_image_profile_get MCP tool is the same read.
Response
prompt_block is plain sentences rendered from the imagery side of the brand guide; avoid_list is the forbidden phrases plus the imagery don’ts; reference_images is the primary logo first (role logo, id logo_primary), then up to three Media Library images tagged brand_reference (role brand, id = the media asset id), newest first. To mark an approved brand image, add brand_reference to its tags with PATCH /api/olympus/marketing/media/{assetId}. See The brand image profile.

Performance and Leads

/marketing/content/views
Batch page and lead stats for up to 200 content items, the read behind the list’s Leads column. Requires marketing.content read. The Olympus twin is POST /api/olympus/marketing/content/views.
Request Body
Response
path is site-absolute; the query string and fragment are stripped and the trailing slash removed, and the key in stats carries that normalised path. form_submits is what the tracking embed saw in the browser; leads is what reached the forms ledger, with spam, duplicates and deleted rows excluded; contacts is the CRM contacts those rows resolved to. A pair with no page views and no ledger rows is absent from stats, not zero-filled, and a project the account does not own is omitted without an error. When the analytics collector is unreachable the response is a 200 with stats: {} and degraded: true: read degraded before reading an absent key as zero. More than 200 items, or no items, is a 400. Nothing is written.
/marketing/content/{id}/scorecard
The per-piece scorecard the editor’s Performance section shows, computed now for ?window (7d, 30d, 90d or all; default 30d), plus last_stored, the date and computed_at of the newest nightly row, or null before the first nightly run. Requires marketing.content read.
/olympus/marketing/content/{id}/analytics
Olympus API key (the content_analytics_get MCP tool). The same scorecard and last_stored, plus data, the stored daily rows the nightly writer keeps (one per closed UTC day; views and unique_views are that day’s own counts, external_analytics carries the rolling 30-day scorecard as of that night), newest first, paged with page and limit (default 30, max 100) and filtered with from_date and to_date, with pagination and a content_summary sourced from the live scorecard.
Response (the scorecard, the same on both)
views, visitors and form_submits are null when the piece has no site page (path is null) or the collector could not answer (degraded.clickhouse is true); they are never 0 in either case. leads, contacts and attributed_contacts come from Postgres and always answer. deals is null when there were no contacts to roll up; lead_rate is leads / views to four decimals, null when views is null or zero. rank.keywords are the rank-tracking rows publish-to-site seeded for the item; social sums the latest snapshot of every post carrying linked_content_id. See The scorecard.

Campaign ROI

/marketing/reports/campaign-roi
Attributed contacts, deals and revenue per marketing asset, content items included, from the credit table through the shared revenue engine: the same builder as the Reports hub. Requires marketing.reports read. The Olympus twin is GET /api/olympus/marketing/reports/campaign-roi (the marketing_campaign_roi MCP tool). Read-only.
Query Parameters Response
Money is integer cents in each source’s own currency, not FX-normalised; mixed_currency is true when the sums span more than one currency. truncated is true when more than 200 assets were cut, the biggest contact sets kept. A content item is credited when a visitor arrived on a link carrying utm_medium=content and utm_content=<its slug>, the keys the repurpose source package and the weekly digest stamp. See UTM crediting.

Proof Pack

/marketing/content/proof-pack
The account’s proof in one read: public consented testimonials, review text, the first inbound message of support tickets in the segment, call summaries, completed-survey free text, measured results from the active before/after grids and the objection library with its best response. Requires marketing.content read. The Olympus twin is GET /api/olympus/marketing/content/proof-pack (the content_proof_pack MCP tool). Read-only.
Query Parameters Response
consent is read from the rows, never assumed: true (testimonial, review, grid result) may be quoted verbatim with its attribution; false (ticket, call, survey, objection) is internal voice of customer to paraphrase without a name. citation is the marker the pre-publish check accepts as a source beside a figure. Entries are interleaved in the order the stage calls for; text is at most 600 characters. A source that cannot be read is reported with ok: false in sources and a line in notes, and the other sources still return.

Case Study

/marketing/content/case-study
Draft a case study from a won CRM deal and save it as a content item of type case_study in draft, at the Decision stage. Requires marketing.content create; the row is attributed to the user. The Olympus twin is POST /api/olympus/marketing/content/case-study (the content_case_study_draft MCP tool). The draft holds the request open for up to three minutes and honours Idempotency-Key, so a retry replays the first answer instead of saving a second row.
Request Body
Response
The body has five sections (The problem, What we did, Results, In their words, What this means for you); every result line carries [source: before_after_grid:<id>] and the quote [source: reputation_testimonial:<id>]. Numbers never come from the model: the results are parsed from the grid’s measurable results, and the quote is copied from the testimonial row and never rewritten. The editor shows the record in its five case-study sections, with the sources read-only. See Proof and case studies.

Research

/marketing/content/{id}/research
The stored research for the item: settings.research and the knowledge artifact it points at, each null before the first run. Requires marketing.content read. The Olympus twin is GET /api/olympus/marketing/content/{id}/research (the content_research_get MCP tool).
/marketing/content/{id}/research
Run the research for the item: every knowledge base in the account first, then the SERP for the target keyword, then up to max_sources web pages, extraction with a verbatim quote per claim, indexing of every page used into the account’s Content research knowledge base, the artifact, and settings.research stamped last. Requires marketing.content update. The Olympus twin is POST /api/olympus/marketing/content/{id}/research (content_research_run). Synchronous, up to 300 seconds: use a client timeout of 240 seconds or more and send an Idempotency-Key.
Request Body (every field optional) Response (201)
Every claim’s quote is copied verbatim from the passage it cites; a quote the run cannot find in the passage is dropped and counted in warnings. kind is web for a fetched page (with source_url) and kb for a knowledge-base passage (source_url is null; cite the knowledge base). extraction is fallback and confidence_score is 0 when no model key is configured: the passages themselves are the claims. A monthly SEO research cap hit returns serp: null and a gap, not an error; a page over 60,000 characters is skipped and reported as a gap; one source failing to index is reported (indexed: false) and the run continues. A re-run refreshes the same artifact (artifact_created: false) and never re-indexes a URL the knowledge base already holds (already_indexed: true). The stamp is at most 8,000 characters (sources and gaps trimmed to 10) and is merged into settings, so sibling keys survive.
/olympus/marketing/content/research
Olympus API key (content_research_topic). The same run for a topic that has no content item yet: topic (required), keyword, avatar_id, project_id and the same knobs. Nothing is stamped; the artifact is the deliverable and its id can be attached to an item later. GET on the same path lists the artifacts in the account’s Content research knowledge base (every type), newest first, with artifact_type, content_id, is_verified, page and limit as filters; knowledge_base_id is null and data empty before the first run created the KB.
See Research with the knowledge base.

Knowledge Artifacts

/olympus/knowledge-bases/artifacts
Olympus API key (kb_artifacts_list). Every knowledge artifact in the account, by type, without knowing the knowledge base id first, newest first. Query artifact_type (content_research, serp_brief, positioning, proof_pack, case_study, data_study, or any type a writer stored), kb_id, content_id (artifacts whose content_json.content_id matches), is_verified (true or false), page (default 1) and limit (default 20, max 100); a page or limit that is not a positive number is read as the default.
Response
/olympus/knowledge-bases/artifacts/{artifactId}
Olympus API key (kb_artifact_get). One artifact by id, the id a settings.research, settings.serp_brief or settings.proof_pack stamp carries. 404 when the artifact’s knowledge base is not in the account, 400 for a malformed id. Returns { data: artifact }.
The per-knowledge-base list at GET /api/olympus/marketing/knowledge-bases/{kbId}/artifacts is unchanged; these two are the account-wide view. An artifact’s markdown is also indexed as a document in its knowledge base, so kb_search finds it semantically and the hit carries metadata.artifact_id and metadata.artifact_type. See Artifacts, and how to find them.

Content Comments

List Comments

/marketing/content/{id}/comments
Get all comments on a content item.

Add Comment

/marketing/content/{id}/comments
Add a comment to a content item.

Content Reviews

/marketing/content/{id}/reviews
Get review status and history for a content item.
/marketing/content/{id}/reviews
Submit a review (approve or request changes).

Version History

/marketing/content/{id}/versions
List all versions of a content item.

Image Upload

/marketing/content/{id}/upload-image
Upload an image to attach to a content item.
/marketing/content/{id}/delete-image
Remove an image from a content item.