MarketScale
Publish API · Internal

Publish articles and creator-hub posts via HTTPS.

Two JSON endpoints. Bearer token auth. Idempotent on slug: push the same payload twice and the second call updates the first. Images and videos are downloaded and pushed to Cloudinary on your behalf, so posts render with native inline media (no Wistia intermediary required). Bring your own article and we keep it verbatim and enrich it; send just a title with blog: false and we write the article for you.

01

Authentication

Every request must include an Authorization header carrying a bearer token. The token is set on the server as the PUBLISH_API_KEY environment variable; ask your MarketScale contact for the value.

Authorization: Bearer <PUBLISH_API_KEY>

Requests without a token (or with the wrong token) return 401. If the server has no PUBLISH_API_KEY configured at all, every request returns 503 until it's set.

02

Publish an article

POST /api/publish/article: write an article into one of the 16 industry collections.

FieldTypeNotes
collection*stringOne of the 16 industry slugs (e.g. "healthcare", "pro-av").
title*stringArticle headline.
blogbooleantrue: you supply the article in "content"; it is kept verbatim and enriched. false: MarketScale writes the article from title, excerpt, and tags. Omitted: inferred from whether "content" is present.
contentstring | string[]Your article body: a string with double-newline paragraph breaks, or an array of paragraph strings. Required when "blog" is true; ignored when "blog" is false. When omitted, the body is generated.
slugstringURL slug. Auto-derived from title if omitted.
excerptstringOne-line summary (≤600 chars).
authorstringAuthor display name.
publishedAtstringISO 8601. Defaults to now.
featuredImageUrlstringHTTPS URL. Downloaded and uploaded to Cloudinary on publish.
videoUrlstringHTTPS URL to a video file (mp4/mov/webm). Downloaded and uploaded to Cloudinary; the post renders with an inline <video> player. Preferred over Wistia.
tagsstring[]Free-form tag strings.
wistiaMediaIdstringLegacy. Single Wistia media id. Use videoUrl instead for new posts.
aiFormatbooleanDefault true. AI pass adds section headings + pull-quotes without changing wording. Set to false for time-sensitive publishes (skips a 5 to 15s Claude call).

* required

Request

curl -X POST https://marketscale.com/api/publish/article \
  -H "Authorization: Bearer $PUBLISH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "collection": "healthcare",
    "title": "Inside the new specialty-pharmacy model",
    "excerpt": "How a specialty pharmacy aligns patients, providers, and payers.",
    "author": "Lea Sims",
    "content": "Opening paragraph.\n\nSecond paragraph.",
    "featuredImageUrl": "https://example.com/cover.jpg",
    "videoUrl": "https://studio.marketscale.com/exports/sp-model.mp4",
    "tags": ["specialty-pharmacy", "value-based-care"]
  }'

Response

{
  "status": "created",
  "id": "67df9b4a3c1a9f6f8e2b1d34",
  "slug": "inside-the-new-specialty-pharmacy-model",
  "collection": "healthcare",
  "url": "https://marketscale.com/industries/healthcare/inside-the-new-specialty-pharmacy-model"
}

Re-posting the same slug returns "status": "updated" with 200 instead of 201. The response also carries contentSource: "provided" when your article was kept and enriched, "generated" when MarketScale wrote it.

03

Publish to a creator hub

POST /api/publish/channel-post: write a post that surfaces under a specific creator hub (Show). The hub is identified by its channelId, which you set on the Show record in Payload admin.

FieldTypeNotes
channelId*stringMatches the Channel ID field set on a Show in Payload.
title*stringPost headline.
blogbooleantrue: you supply the post in "content"; it is kept verbatim and enriched. false: MarketScale writes it from title, excerpt, and tags. Omitted: inferred from whether "content" is present.
contentstring | string[]Your post body. Required when "blog" is true; generated when omitted or "blog" is false.
slugstringURL slug. Auto-derived if omitted.
excerptstringOne-line summary.
authorstringDisplay name.
publishedAtstringISO 8601. Defaults to now.
featuredImageUrlstringHTTPS image URL.
videoUrlstringHTTPS URL to a video file. Downloaded + uploaded to Cloudinary; inline <video> player. Preferred over Wistia.
tagsstring[]Free-form tags.
wistiaMediaIdstringLegacy. Use videoUrl for new posts.
aiFormatbooleanDefault true. AI pass adds headings + pull-quotes without changing wording. Set false to skip.

* required

Request

curl -X POST https://marketscale.com/api/publish/channel-post \
  -H "Authorization: Bearer $PUBLISH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channelId": "tekniplex-prod",
    "title": "IPS Global Sales Meeting · day three",
    "excerpt": "Three days of cross-regional collaboration in Mexico City.",
    "author": "Jane Smith",
    "content": "Opening paragraph.\n\nSecond paragraph.",
    "featuredImageUrl": "https://example.com/cover.jpg",
    "videoUrl": "https://studio.marketscale.com/exports/ips-day-three.mp4",
    "tags": ["sales", "global"]
  }'

Response

{
  "status": "created",
  "id": "67df9b4a3c1a9f6f8e2b1d34",
  "slug": "ips-global-sales-meeting-day-three",
  "channelSlug": "tekniplex",
  "channelName": "TekniPlex",
  "collection": "business-services",
  "url": "https://marketscale.com/industries/business-services/ips-global-sales-meeting-day-three",
  "hubUrl": "https://marketscale.com/creator-hubs/tekniplex"
}

The post lives inside the show's industry collection but carries the show's channelName, so it appears on both the industry feed and the creator hub. Hub pages are revalidated on publish, so the post is visible at hubUrl immediately.

Idempotency is scoped to the hub: re-posting a slug updates the post only when it belongs to the same hub. A slug owned by another hub is never overwritten; the new post gets a suffixed slug instead. If the Show has no industry set, the response includes a warning and the post is stored under business-services.

04

Errors

FieldTypeNotes
400errorValidation: missing required field, unknown collection, field exceeds max length, malformed JSON.
401errorBearer token missing or incorrect.
404errorchannelId did not match any Show.
500errorInternal error during create / update. Check server logs.
503errorPUBLISH_API_KEY is not configured on the server.

This page is unlisted. Direct-link access only.