Outcome
Creates a draft article in the workspace. A draft is never publicly visible. Publishing is a separate, gated path: review then approval then publish.
Before you start
- Verify identity and the intended environment with topolo whoami before selecting an explicitly authorized organization.
- Discover the published workspace:write permission.
- Discover an accessible Blog workspace and set WORKSPACE_ID to that exact returned id. Pass workspace binding separately from action input.
- Review the actual state change and confirm the unchanged plan before execution. Fixture ids and provider responses grant no live authority.
Discover the target
topolo whoami --json
topolo actions get app_topolo_blog.articles.create --detail --json
topolo workspaces list topolo-blog --json
- publicationId: Exact destination id from publications.list or publications.create; a display name or slug is not an id.
Request
POST /api/articles
Inspect parameters and test this action.
Input fields
| Field | Required | Meaning |
|---|---|---|
title | Yes | Article title. Updating it edits the current revision and resets review approval. |
slug | No | Requested route slug. Discover the normalized slug and canonical URL in the returned record. |
publicationId | No | Exact destination id from publications.list or publications.create; a display name or slug is not an id. |
excerpt | No | Public standfirst, stored separately from body. |
body | No | Complete ordered structured block array. Updating replaces the whole body, not a fragment; inspect nested block fields in Parameters. |
tags | No | Complete tag list; values are normalized and deduplicated by article writes. |
seriesName | No | Series name, or null to remove series membership. |
seriesPosition | No | Positive position in a series, or null to clear it. |
seoTitle | No | SEO title override, or null to clear it. |
seoDescription | No | SEO description override, or null to clear it. |
ogImageUrl | No | An HTTPS or Blog media URL for Open Graph imagery; confirm asset ownership. |
canonicalUrl | No | Canonical HTTPS article URL; inspect returned routing after write. |
authorName | No | Named author shown with the article; this does not change credential identity. |
Worked examples
Documentation source snapshot: TopoloBlog 80d6961207a4ca688b7e9edb947dda720051ad32 (tree 534a285e739a27c1ea9e2c187ce8863824f6c590). The examples retain local fixture captures labeled baseline 2c64c35bf291a47bb3a0c597dcea46ccb47e2a08; their exact executed working tree is not established here. They were not rerun at this documentation snapshot. The production catalog marker topolo.app.json is not a deployed worker revision. Recovery metadata read-back on 18 October 2026 associates the current production Blog API and web deployments with this source through the 17 October release receipt. This establishes applicable deployed source; it does not make these examples current production captures.
Actual exported Blog Worker, local Miniflare D1/R2 and all committed migrations. Auth, Insights, DNS, Cloudflare for SaaS, error reporting, queue and scheduled-workflow boundaries are synthetic and outbound fetch is sealed. No deployed provider, delivery or scheduled execution outcome is established. English examples use the packaged test translation release; article checks and widget labels follow the verified request locale. No live translation release is proved by this fixture.
Save a reviewed input as payload.json. Replace fixture identifiers using discovery in the authorized context.
topolo actions validate app_topolo_blog.articles.create --data @payload.json --json
topolo actions plan app_topolo_blog.articles.create --resource-type workspace --resource-id "$WORKSPACE_ID" --data @payload.json --confirm --json
topolo actions call app_topolo_blog.articles.create --resource-type workspace --resource-id "$WORKSPACE_ID" --data @payload.json --confirm --detail --json
MCP uses the same reviewed input. Replace the synthetic workspace resourceId through discovery when a binding is shown:
{
"tool": "topolo_prepare_action",
"arguments": {
"actionId": "app_topolo_blog.articles.create",
"input": {
"title": "A fixture article",
"excerpt": "Source-bound example",
"body": [
{
"type": "paragraph",
"text": "This is controlled documentation content."
}
],
"seoTitle": "A fixture article",
"seoDescription": "A source-bound documentation fixture."
},
"resourceType": "workspace",
"resourceId": "ws_blog_fixture",
"confirm": true
}
}
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_blog.articles.create",
"input": {
"title": "A fixture article",
"excerpt": "Source-bound example",
"body": [
{
"type": "paragraph",
"text": "This is controlled documentation content."
}
],
"seoTitle": "A fixture article",
"seoDescription": "A source-bound documentation fixture."
},
"resourceType": "workspace",
"resourceId": "ws_blog_fixture",
"confirm": true,
"detail": true
}
}
Successful response · HTTP 201
Input · payload.json:
{
"title": "A fixture article",
"excerpt": "Source-bound example",
"body": [
{
"type": "paragraph",
"text": "This is controlled documentation content."
}
],
"seoTitle": "A fixture article",
"seoDescription": "A source-bound documentation fixture."
}
Source-reviewed illustration (retained local fixture response; not a current production capture):
{
"article": {
"id": "article_5c228170-0ed2-474d-bd5d-d91947d7256e",
"organizationId": "org_blog_fixture",
"workspaceId": "ws_blog_fixture",
"publicationKey": "ws-blog-fixture",
"publicationId": "publication_f46fe585-c4f0-4d96-8cda-a8970fdd0f88",
"publicationName": "Primary publication",
"title": "A fixture article",
"slug": "a-fixture-article",
"excerpt": "Source-bound example",
"body": [
{
"type": "paragraph",
"text": "This is controlled documentation content."
}
],
"tags": [],
"seriesName": null,
"seriesPosition": null,
"seoTitle": "A fixture article",
"seoDescription": "A source-bound documentation fixture.",
"ogImageUrl": null,
"canonicalUrl": "https://blog.topolo.app/p/ws-blog-fixture/a-fixture-article",
"authorName": "Topolo Technology",
"status": "draft",
"reviewStatus": "draft",
"reviewRequestedAt": null,
"approvedRevisionNumber": null,
"approvedByUserId": null,
"approvedAt": null,
"scheduledFor": null,
"scheduledRevisionNumber": null,
"publishedAt": null,
"publishedRevisionNumber": null,
"hasUnpublishedChanges": false,
"revisionNumber": 1,
"createdByUserId": "user_blog_fixture",
"createdAt": "2026-10-06T07:31:32.474Z",
"updatedAt": "2026-10-06T07:31:32.474Z"
}
}
Call app_topolo_blog.articles.get and confirm the article exists as an unpublished draft.
Refused request · HTTP 401 · auth_error
Input · payload.json:
{
"title": "A fixture article",
"excerpt": "Source-bound example",
"body": [
{
"type": "paragraph",
"text": "This is controlled documentation content."
}
],
"seoTitle": "A fixture article",
"seoDescription": "A source-bound documentation fixture."
}
Source-reviewed illustration (retained local fixture response; not a current production capture):
{
"error": "Authentication token required"
}
Sign in again in the intended environment using a valid credential. Preserve the returned handler message; SDK auth_error can represent several authentication refusals.
Verify the result
- Call app_topolo_blog.articles.get and confirm the article exists as an unpublished draft.
Errors and recovery
- HTTP 401 ·
auth_error: Sign in again in the intended environment using a valid credential. Preserve the returned handler message; SDK auth_error can represent several authentication refusals.
Inspect the raw handler error as well as the SDK code. These examples establish observed local refusals, not every possible provider failure.
Recovery boundary
Delete the draft. Nothing was published, so no public URL existed.
Related actions
- Update article (
app_topolo_blog.articles.update): Update an article and append an immutable revision. Provided fields replace their previous values (body is replaced whole, not merged), and any edit resets review status to draft. - Request article review (
app_topolo_blog.articles.review.request): Submit the current article revision for editorial review. - Delete article: Permanently delete an article and its immutable revisions from the selected editorial workspace.
Evidence
Actual exported Blog Worker, local Miniflare D1/R2 and all committed migrations. Auth, Insights, DNS, Cloudflare for SaaS, error reporting, queue and scheduled-workflow boundaries are synthetic and outbound fetch is sealed. No deployed provider, delivery or scheduled execution outcome is established. English examples use the packaged test translation release; article checks and widget labels follow the verified request locale. No live translation release is proved by this fixture.
Documentation history
18 October 2026: Architecture reviewed the retained action guide against the pinned source declaration and named implementation boundaries, qualified local-capture provenance, and prepared paired human and agent amendments. This review does not record a product release, new fixture execution or publication.
2026-10-18: Related guides that cannot yet be published target-first are listed as exact related action references. Captured requests, responses and schemas are unchanged.
2026-10-18: Architecture accepted the paired coauthor delta and qualified the current 80D deployment association from existing Recovery evidence. Examples remain source-reviewed retained-fixture illustrations; no new execution or guide publication is recorded.