application · active
Blog
Governed editorial workspace for drafts, immutable revisions, publication scheduling, media, SEO metadata, and public headless article delivery.
Documentation map
- Blog — Write, schedule, publish, and distribute governed articles.
Authority and runtime
- System ID
topolo-blog- App IDs
- app_topolo_blog
- Owners
- platform-engineering
- Repositories
- apps/TopoloBlog
- Hosts
- https://blog.topolo.app, https://blog.stg.topolo.us, https://blog.topolo.dev
- Dependencies
- topolo-auth, topolo-nexus, topolo-platform
Security and data ownership
- Risk tier
- internal
- Tenant isolation
- organization_scoped
- Privacy classification
- confidential
- Storage
- d1, r2, queue, workflow
- Export and deletion
- implemented
- Enterprise ready
- no
Source-derived capability inventory
Source revisions: apps/TopoloBlog@ea26b09a5159a13506f1bc6b020273fb1a9396a1
Declared actions: 42 · API routes: 5 · UI routes: 12
{
"id": "topolo-blog",
"name": "Blog",
"slug": "topolo-blog",
"kind": "application",
"visibility": "public",
"repo_paths": [
"apps/TopoloBlog"
],
"source_revisions": [
{
"source_path": "apps/TopoloBlog",
"repository": "apps/TopoloBlog",
"revision": "ea26b09a5159a13506f1bc6b020273fb1a9396a1",
"ref": "origin/staging"
}
],
"source_counts": {
"source_files": 68,
"test_files": 31,
"test_cases": 0,
"migration_files": 4,
"database_tables": 0,
"manifests": 1,
"deploy_targets": 2,
"actions": 42,
"mobile_contracts": 0,
"notifications": 1,
"package_manifests": 1,
"deployment_configs": 0
},
"manifests": [
{
"source_path": "apps/TopoloBlog/topolo.app.json",
"service_slug": "topolo-blog",
"name": "topolo-blog",
"app_id": "app_topolo_blog",
"compatibility_date": "2026-05-05",
"primary_target": null,
"environments": [
"development",
"production",
"staging"
],
"targets": [
{
"name": "api",
"kind": "worker",
"directory": "apps/api",
"main": "src/worker.ts",
"worker_name": "topolo-blog-api",
"subdomain": null,
"healthcheck_path": "/api/health",
"variable_names": [
"AUTH_BASE_URL",
"INSIGHTS_API_URL",
"INSIGHTS_WORKSPACE_ID",
"NEXUS_GATEWAY_URL",
"TOPOLO_NOTIFY_URL",
"TOPOLO_ONE_REVALIDATE_URL"
],
"secret_names": [],
"bindings": [
{
"kind": "d1",
"binding": "BLOG_CORE_DB",
"target": null
},
{
"kind": "r2",
"binding": "APP_ASSETS",
"target": null
},
{
"kind": "workflows",
"binding": "APP_WORKFLOW",
"target": null
}
]
},
{
"name": "web",
"kind": "worker",
"directory": "apps/web",
"main": "src/worker.ts",
"worker_name": "topolo-blog",
"subdomain": "blog",
"healthcheck_path": "/api/health",
"variable_names": [
"INSIGHTS_SITE_KEY"
],
"secret_names": [],
"bindings": [
{
"kind": "services",
"binding": "API",
"target": null
}
]
}
],
"notifications": [
"blog.article.published"
],
"notification_contract": {
"source_path": "topolo.notification-contracts.json",
"role": "producer",
"schema_version": 1,
"owner_app_id": "app_topolo_blog",
"events": [
{
"type": "blog.article.published",
"version": 1,
"description": "A persisted article revision became publicly readable from a TopoloBlog publication.",
"status": "published",
"payloadSchema": {
"type": "object",
"required": [
"title",
"body",
"object_id",
"occurred_at",
"article_id",
"publication_key",
"canonical_url",
"revision_number"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"body": {
"type": "string",
"minLength": 1
},
"surface": {
"enum": [
"notification",
"action"
]
},
"priority": {
"enum": [
"low",
"normal",
"high",
"urgent"
]
},
"severity": {
"enum": [
"info",
"success",
"warning",
"critical"
]
},
"category": {
"type": "string"
},
"object_type": {
"type": "string"
},
"object_id": {
"type": "string",
"minLength": 1
},
"cta_url": {
"type": "string",
"format": "uri"
},
"cta_label": {
"type": "string"
},
"occurred_at": {
"type": "string",
"format": "date-time"
},
"article_id": {
"type": "string",
"minLength": 1
},
"publication_key": {
"type": "string",
"minLength": 1
},
"canonical_url": {
"type": "string",
"format": "uri"
},
"revision_number": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": false
},
"examples": [
{
"title": "Published: Agent-native business software",
"body": "The article is now publicly available.",
"surface": "notification",
"priority": "normal",
"severity": "success",
"category": "blog",
"object_type": "blog_article",
"object_id": "article_agent_native_business_software",
"cta_url": "https://topolo.io/blog/agent-native-business-software",
"cta_label": "View article",
"occurred_at": "2026-08-09T00:00:00.000Z",
"article_id": "article_agent_native_business_software",
"publication_key": "topolo",
"canonical_url": "https://topolo.io/blog/agent-native-business-software",
"revision_number": 3
}
],
"dataClassification": "public",
"recipients": {
"modes": [
"workspace_member"
],
"externalAddress": "forbidden"
},
"idempotency": {
"required": true,
"pattern": "^blog:article:published:"
},
"sensitiveFields": []
}
]
},
"actions": [
{
"name": "widget.get",
"title": "Get widget summary",
"description": "Get the TopoloBlog widget summary.",
"method": "GET",
"path": "/api/widget",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"widgets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"snapshot": {
"type": "object",
"properties": {
"summary": {
"type": "string"
}
},
"required": [
"summary"
],
"additionalProperties": {}
},
"actions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": "string"
},
"link": {
"type": "string"
},
"primary": {
"type": "boolean"
}
},
"required": [
"id",
"label",
"link"
],
"additionalProperties": false
}
},
"appId": {
"type": "string"
},
"serviceName": {
"type": "string"
},
"lastUpdated": {
"type": "string"
}
},
"required": [
"type",
"snapshot",
"actions",
"appId",
"serviceName",
"lastUpdated"
],
"additionalProperties": {}
}
}
},
"required": [
"success",
"widgets"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=widget.get",
"resource": {
"kind": "widget",
"idPath": "$.id"
},
"effects": [
"Reads widget data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for widget.get."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/widget",
"body": null
},
"effects": "Reads widget data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=widget.get",
"resource": {
"kind": "widget",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/widget",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "workspace.bootstrap",
"title": "Get workspace bootstrap",
"description": "Get the signed TopoloBlog workspace bootstrap payload.",
"method": "GET",
"path": "/api/bootstrap",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"additionalProperties": {}
},
"organization": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
}
},
"required": [
"id",
"name",
"slug"
],
"additionalProperties": {}
},
{
"type": "null"
}
]
}
},
"required": [
"user",
"organization"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=workspace.bootstrap",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"effects": [
"Reads workspace data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for workspace.bootstrap."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/bootstrap",
"body": null
},
"effects": "Reads workspace data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=workspace.bootstrap",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/bootstrap",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "overview.get",
"title": "Get publishing overview",
"description": "Get publishing counts, upcoming releases, and recent editorial work.",
"method": "GET",
"path": "/api/overview",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"overview": {
"type": "object",
"properties": {
"counts": {
"type": "object",
"properties": {
"draft": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"scheduled": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"published": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"media": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"publications": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"draft",
"scheduled",
"published",
"media",
"publications"
],
"additionalProperties": false
},
"upcoming": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"recent": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
}
},
"required": [
"counts",
"upcoming",
"recent"
],
"additionalProperties": false
}
},
"required": [
"overview"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=overview.get",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"effects": [
"Reads workspace data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for overview.get."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/overview",
"body": null
},
"effects": "Reads workspace data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=overview.get",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/overview",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "analytics.overview",
"title": "Get readership analytics",
"description": "Get the shared Insights readership overview for this editorial workspace.",
"method": "GET",
"path": "/api/analytics",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"days": {
"type": "integer",
"minimum": 1,
"maximum": 90
}
},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {},
"additionalProperties": {}
}
},
"required": [
"data"
],
"additionalProperties": {}
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=analytics.overview",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"effects": [
"Reads workspace data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {
"days": 30
},
"expected": "A response matching the published outputSchema for analytics.overview."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"days": 30
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/analytics",
"body": null
},
"effects": "Reads workspace data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=analytics.overview",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/analytics",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.list",
"title": "List articles",
"description": "Search, filter, sort, and paginate articles in the selected editorial workspace.",
"method": "GET",
"path": "/api/articles",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"query": {
"type": "string",
"maxLength": 160
},
"status": {
"type": "string",
"enum": [
"all",
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"all",
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"sort": {
"type": "string",
"enum": [
"updatedAt",
"title",
"publishedAt"
]
},
"order": {
"type": "string",
"enum": [
"asc",
"desc"
]
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"cursor": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articles": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"total": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"nextCursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"articles",
"total",
"nextCursor"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.list",
"resource": {
"kind": "article",
"idPath": "$.items[].id"
},
"effects": [
"Reads article data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for articles.list."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/articles",
"body": null
},
"effects": "Reads article data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.list",
"resource": {
"kind": "article",
"idPath": "$.items[].id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/articles",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.preview",
"title": "Preview article",
"description": "Render an unsaved article draft to the same HTML used by the published reader surface.",
"method": "POST",
"path": "/api/articles/preview",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"maxLength": 160,
"description": "Article headline; renders as the page H1 and seeds the slug when slug is omitted."
},
"slug": {
"description": "URL path segment. Omit to derive it from the title.",
"type": "string",
"maxLength": 120
},
"publicationId": {
"description": "Target publication id from publications.list. Omit to use the workspace default publication.",
"type": "string",
"minLength": 1
},
"excerpt": {
"type": "string",
"maxLength": 320
},
"body": {
"description": "Ordered article content as typed blocks (paragraph, heading, list, image, quote, divider, code, callout). Text fields accept inline markdown: **bold**, *italic*, `code`, [label](https://…).",
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"maxItems": 12,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 48
}
},
"seriesName": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string",
"format": "uri"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string",
"format": "uri"
},
"authorName": {
"type": "string",
"minLength": 1,
"maxLength": 100
}
},
"required": [
"title"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"bodyHtml": {
"type": "string"
}
},
"required": [
"bodyHtml"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.preview",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Reads article data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {
"title": "Preview article",
"body": [
{
"type": "paragraph",
"text": "Preview body."
}
]
},
"expected": "A response matching the published outputSchema for articles.preview."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"title": "Preview article",
"body": [
{
"type": "paragraph",
"text": "Preview body."
}
]
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/preview",
"body": {
"title": "Preview article",
"body": [
{
"type": "paragraph",
"text": "Preview body."
}
]
}
},
"effects": "Reads article data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.preview",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/preview",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.get",
"title": "Get article",
"description": "Get one article from the selected editorial workspace.",
"method": "GET",
"path": "/api/articles/{articleId}",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.get",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Reads article data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.get."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/articles/article_example",
"body": null
},
"effects": "Reads article data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.get",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/articles/*",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.revisions.list",
"title": "List article revisions",
"description": "List the immutable revisions for an article.",
"method": "GET",
"path": "/api/articles/{articleId}/revisions",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"revisions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"articleId": {
"type": "string"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"snapshot": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId"
],
"additionalProperties": false
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
}
},
"required": [
"id",
"articleId",
"revisionNumber",
"snapshot",
"createdByUserId",
"createdAt"
],
"additionalProperties": false
}
}
},
"required": [
"revisions"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.revisions.list",
"resource": {
"kind": "article",
"idPath": "$.items[].id"
},
"effects": [
"Reads article data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.revisions.list."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/articles/article_example/revisions",
"body": null
},
"effects": "Reads article data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.revisions.list",
"resource": {
"kind": "article",
"idPath": "$.items[].id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/articles/*/revisions",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.revisions.restore",
"title": "Restore article revision",
"description": "Restore an immutable revision as a new unpublished article revision.",
"method": "POST",
"path": "/api/articles/{articleId}/revisions/{revisionNumber}/restore",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
},
"revisionNumber": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"articleId",
"revisionNumber"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.revisions.restore",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example",
"revisionNumber": 2
},
"expected": "A response matching the published outputSchema for articles.revisions.restore."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example",
"revisionNumber": 2
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/revisions/2/restore",
"body": {
"articleId": "article_example",
"revisionNumber": 2
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.revisions.restore",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/*/revisions/*/restore",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.create",
"title": "Create article",
"description": "Create a new draft article in the selected editorial workspace. Always yields a draft: to go live, request review, approve, then publish or schedule.",
"method": "POST",
"path": "/api/articles",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"maxLength": 160,
"description": "Article headline; renders as the page H1 and seeds the slug when slug is omitted."
},
"slug": {
"description": "URL path segment. Omit to derive it from the title.",
"type": "string",
"maxLength": 120
},
"publicationId": {
"description": "Target publication id from publications.list. Omit to use the workspace default publication.",
"type": "string",
"minLength": 1
},
"excerpt": {
"type": "string",
"maxLength": 320
},
"body": {
"description": "Ordered article content as typed blocks (paragraph, heading, list, image, quote, divider, code, callout). Text fields accept inline markdown: **bold**, *italic*, `code`, [label](https://…).",
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"maxItems": 12,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 48
}
},
"seriesName": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string",
"format": "uri"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string",
"format": "uri"
},
"authorName": {
"type": "string",
"minLength": 1,
"maxLength": 100
}
},
"required": [
"title"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.create",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"title": "How we ship every week",
"excerpt": "The release habits that keep our team shipping weekly without breaking production.",
"body": [
{
"type": "paragraph",
"text": "Shipping weekly is a **habit**, not a heroic effort. This post covers the *three* practices that make it routine."
},
{
"type": "heading",
"level": 2,
"text": "Keep changes small"
},
{
"type": "list",
"style": "unordered",
"items": [
"**Small diffs:** easier to review and revert.",
"**Feature flags:** decouple deploy from release — see [our guide](https://example.com/flags)."
]
},
{
"type": "quote",
"text": "If a release is scary, do it more often.",
"attribution": "Engineering handbook"
},
{
"type": "code",
"language": "bash",
"code": "git switch -c release/weekly\ngit push origin release/weekly"
},
{
"type": "callout",
"tone": "info",
"title": "Draft first",
"text": "Creating an article always produces a draft. Request review, approve, then publish or schedule it."
},
{
"type": "divider"
},
{
"type": "heading",
"level": 3,
"text": "What we measure"
},
{
"type": "paragraph",
"text": "Lead time, review latency, and the rollback count — tracked per `release` tag."
}
],
"tags": [
"engineering",
"process"
]
},
"expected": "A response matching the published outputSchema for articles.create."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata",
"nextActionIds": [
"app_topolo_blog.articles.update",
"app_topolo_blog.media.upload",
"app_topolo_blog.articles.checks.get",
"app_topolo_blog.articles.review.request"
]
},
"documentation": {
"example_input": {
"title": "How we ship every week",
"excerpt": "The release habits that keep our team shipping weekly without breaking production.",
"body": [
{
"type": "paragraph",
"text": "Shipping weekly is a **habit**, not a heroic effort. This post covers the *three* practices that make it routine."
},
{
"type": "heading",
"level": 2,
"text": "Keep changes small"
},
{
"type": "list",
"style": "unordered",
"items": [
"**Small diffs:** easier to review and revert.",
"**Feature flags:** decouple deploy from release — see [our guide](https://example.com/flags)."
]
},
{
"type": "quote",
"text": "If a release is scary, do it more often.",
"attribution": "Engineering handbook"
},
{
"type": "code",
"language": "bash",
"code": "git switch -c release/weekly\ngit push origin release/weekly"
},
{
"type": "callout",
"tone": "info",
"title": "Draft first",
"text": "Creating an article always produces a draft. Request review, approve, then publish or schedule it."
},
{
"type": "divider"
},
{
"type": "heading",
"level": 3,
"text": "What we measure"
},
{
"type": "paragraph",
"text": "Lead time, review latency, and the rollback count — tracked per `release` tag."
}
],
"tags": [
"engineering",
"process"
]
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles",
"body": {
"title": "How we ship every week",
"excerpt": "The release habits that keep our team shipping weekly without breaking production.",
"body": [
{
"type": "paragraph",
"text": "Shipping weekly is a **habit**, not a heroic effort. This post covers the *three* practices that make it routine."
},
{
"type": "heading",
"level": 2,
"text": "Keep changes small"
},
{
"type": "list",
"style": "unordered",
"items": [
"**Small diffs:** easier to review and revert.",
"**Feature flags:** decouple deploy from release — see [our guide](https://example.com/flags)."
]
},
{
"type": "quote",
"text": "If a release is scary, do it more often.",
"attribution": "Engineering handbook"
},
{
"type": "code",
"language": "bash",
"code": "git switch -c release/weekly\ngit push origin release/weekly"
},
{
"type": "callout",
"tone": "info",
"title": "Draft first",
"text": "Creating an article always produces a draft. Request review, approve, then publish or schedule it."
},
{
"type": "divider"
},
{
"type": "heading",
"level": 3,
"text": "What we measure"
},
{
"type": "paragraph",
"text": "Lead time, review latency, and the rollback count — tracked per `release` tag."
}
],
"tags": [
"engineering",
"process"
]
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.create",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [
"app_topolo_blog.articles.update",
"app_topolo_blog.media.upload",
"app_topolo_blog.articles.checks.get",
"app_topolo_blog.articles.review.request"
],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.update",
"title": "Update article",
"description": "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.",
"method": "PATCH",
"path": "/api/articles/{articleId}",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 160,
"description": "Article headline; renders as the page H1 and seeds the slug when slug is omitted."
},
"slug": {
"description": "URL path segment. Omit to derive it from the title.",
"type": "string",
"maxLength": 120
},
"publicationId": {
"description": "Target publication id from publications.list. Omit to use the workspace default publication.",
"type": "string",
"minLength": 1
},
"excerpt": {
"type": "string",
"maxLength": 320
},
"body": {
"description": "Ordered article content as typed blocks (paragraph, heading, list, image, quote, divider, code, callout). Text fields accept inline markdown: **bold**, *italic*, `code`, [label](https://…).",
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"maxItems": 12,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 48
}
},
"seriesName": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string",
"format": "uri"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string",
"format": "uri"
},
"authorName": {
"type": "string",
"minLength": 1,
"maxLength": 100
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.update",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example",
"title": "Updated title",
"body": [
{
"type": "paragraph",
"text": "Replaces the whole body: send the complete block array, not a fragment."
}
]
},
"expected": "A response matching the published outputSchema for articles.update."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata",
"nextActionIds": [
"app_topolo_blog.articles.checks.get",
"app_topolo_blog.articles.review.request"
]
},
"documentation": {
"example_input": {
"articleId": "article_example",
"title": "Updated title",
"body": [
{
"type": "paragraph",
"text": "Replaces the whole body: send the complete block array, not a fragment."
}
]
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "PATCH",
"path": "/api/articles/article_example",
"body": {
"articleId": "article_example",
"title": "Updated title",
"body": [
{
"type": "paragraph",
"text": "Replaces the whole body: send the complete block array, not a fragment."
}
]
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.update",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [
"app_topolo_blog.articles.checks.get",
"app_topolo_blog.articles.review.request"
],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "PATCH /api/articles/*",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.delete",
"title": "Delete article",
"description": "Permanently delete an article and its immutable revisions from the selected editorial workspace.",
"method": "DELETE",
"path": "/api/articles/{articleId}",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"deleted": {
"type": "boolean",
"const": true
},
"articleId": {
"type": "string"
}
},
"required": [
"deleted",
"articleId"
],
"additionalProperties": false
},
"target": "api",
"destructive": true,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.delete",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.delete."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "DELETE",
"path": "/api/articles/article_example",
"body": null
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.delete",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "DELETE /api/articles/*",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.review.request",
"title": "Request article review",
"description": "Submit the current article revision for editorial review.",
"method": "POST",
"path": "/api/articles/{articleId}/review/request",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.review.request",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.review.request."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata",
"nextActionIds": [
"app_topolo_blog.articles.review.approve",
"app_topolo_blog.articles.review.changes.request"
]
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/review/request",
"body": {
"articleId": "article_example"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.review.request",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [
"app_topolo_blog.articles.review.approve",
"app_topolo_blog.articles.review.changes.request"
],
"rollback_action_id": null
},
"implementation": {
"status": "declared_unserved",
"route_key": "POST /api/articles/*/review/request",
"evidence": "No matching served route was extracted from canonical staging source."
}
},
{
"name": "articles.review.approve",
"title": "Approve article revision",
"description": "Approve the exact article revision currently under review. Approval is a prerequisite for publish and schedule, and is voided by any later edit.",
"method": "POST",
"path": "/api/articles/{articleId}/review/approve",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.review.approve",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.review.approve."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata",
"nextActionIds": [
"app_topolo_blog.articles.publish",
"app_topolo_blog.articles.schedule"
]
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/review/approve",
"body": {
"articleId": "article_example"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.review.approve",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [
"app_topolo_blog.articles.publish",
"app_topolo_blog.articles.schedule"
],
"rollback_action_id": null
},
"implementation": {
"status": "declared_unserved",
"route_key": "POST /api/articles/*/review/approve",
"evidence": "No matching served route was extracted from canonical staging source."
}
},
{
"name": "articles.review.changes.request",
"title": "Request article changes",
"description": "Return an article under review to its author with changes requested.",
"method": "POST",
"path": "/api/articles/{articleId}/review/changes-requested",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.review.changes.request",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.review.changes.request."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/review/changes-requested",
"body": {
"articleId": "article_example"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.review.changes.request",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "declared_unserved",
"route_key": "POST /api/articles/*/review/changes-requested",
"evidence": "No matching served route was extracted from canonical staging source."
}
},
{
"name": "articles.publish",
"title": "Publish approved article",
"description": "Publish the approved current revision immediately while retaining later edits as unpublished changes. Fails with article_not_approved unless the current revision has been approved via the review actions.",
"method": "POST",
"path": "/api/articles/{articleId}/publish",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.publish",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.publish."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/publish",
"body": {
"articleId": "article_example"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.publish",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/*/publish",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.schedule",
"title": "Schedule approved article",
"description": "Schedule the approved current revision for future publication. Fails with article_not_approved unless the current revision has been approved via the review actions.",
"method": "POST",
"path": "/api/articles/{articleId}/schedule",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
},
"publishAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "Future release time as an ISO 8601 UTC datetime, e.g. 2026-08-20T09:00:00.000Z."
}
},
"required": [
"articleId",
"publishAt"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.schedule",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example",
"publishAt": "2026-08-20T09:00:00.000Z"
},
"expected": "A response matching the published outputSchema for articles.schedule."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata",
"nextActionIds": [
"app_topolo_blog.articles.reschedule",
"app_topolo_blog.articles.schedule.cancel"
]
},
"documentation": {
"example_input": {
"articleId": "article_example",
"publishAt": "2026-08-20T09:00:00.000Z"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/schedule",
"body": {
"articleId": "article_example",
"publishAt": "2026-08-20T09:00:00.000Z"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.schedule",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [
"app_topolo_blog.articles.reschedule",
"app_topolo_blog.articles.schedule.cancel"
],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/*/schedule",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.reschedule",
"title": "Reschedule article",
"description": "Replace the release time for the already scheduled revision.",
"method": "POST",
"path": "/api/articles/{articleId}/reschedule",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
},
"publishAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "Future release time as an ISO 8601 UTC datetime, e.g. 2026-08-20T09:00:00.000Z."
}
},
"required": [
"articleId",
"publishAt"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.reschedule",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example",
"publishAt": "2026-08-21T09:00:00.000Z"
},
"expected": "A response matching the published outputSchema for articles.reschedule."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example",
"publishAt": "2026-08-21T09:00:00.000Z"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/reschedule",
"body": {
"articleId": "article_example",
"publishAt": "2026-08-21T09:00:00.000Z"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.reschedule",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/*/reschedule",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.schedule.cancel",
"title": "Cancel article schedule",
"description": "Cancel the pending scheduled release without changing any currently published revision.",
"method": "POST",
"path": "/api/articles/{articleId}/schedule/cancel",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.schedule.cancel",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.schedule.cancel."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/schedule/cancel",
"body": {
"articleId": "article_example"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.schedule.cancel",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/*/schedule/cancel",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.unpublish",
"title": "Unpublish article",
"description": "Remove the currently published revision from public delivery while retaining editorial history.",
"method": "POST",
"path": "/api/articles/{articleId}/unpublish",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.unpublish",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.unpublish."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/unpublish",
"body": {
"articleId": "article_example"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.unpublish",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/*/unpublish",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.duplicate",
"title": "Duplicate article",
"description": "Create a new draft from an existing article without copying its publication state.",
"method": "POST",
"path": "/api/articles/{articleId}/duplicate",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"publicationKey": {
"type": "string"
},
"publicationId": {
"type": "string"
},
"publicationName": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"seriesName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seriesPosition": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"seoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"seoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"ogImageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"canonicalUrl": {
"type": "string"
},
"authorName": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"reviewRequestedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"approvedByUserId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"approvedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledFor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"scheduledRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedRevisionNumber": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
},
"hasUnpublishedChanges": {
"type": "boolean"
},
"revisionNumber": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdByUserId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"publicationKey",
"publicationId",
"publicationName",
"title",
"slug",
"excerpt",
"body",
"tags",
"seriesName",
"seriesPosition",
"seoTitle",
"seoDescription",
"ogImageUrl",
"canonicalUrl",
"authorName",
"status",
"reviewStatus",
"reviewRequestedAt",
"approvedRevisionNumber",
"approvedByUserId",
"approvedAt",
"scheduledFor",
"scheduledRevisionNumber",
"publishedAt",
"publishedRevisionNumber",
"hasUnpublishedChanges",
"revisionNumber",
"createdByUserId",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.duplicate",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.duplicate."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/article_example/duplicate",
"body": {
"articleId": "article_example"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.duplicate",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/*/duplicate",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.checks.get",
"title": "Check article readiness",
"description": "Run SEO completeness, accessibility, and bounded broken-link checks for an article.",
"method": "GET",
"path": "/api/articles/{articleId}/checks",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleId": {
"type": "string",
"minLength": 1
}
},
"required": [
"articleId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"checks": {
"type": "object",
"properties": {
"checks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"pass",
"warning",
"error"
]
},
"message": {
"type": "string"
}
},
"required": [
"id",
"label",
"status",
"message"
],
"additionalProperties": false
}
},
"links": {
"type": "array",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"ok",
"broken",
"blocked"
]
},
"statusCode": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
]
}
},
"required": [
"url",
"status",
"statusCode"
],
"additionalProperties": false
}
},
"complete": {
"type": "boolean"
}
},
"required": [
"checks",
"links",
"complete"
],
"additionalProperties": false
}
},
"required": [
"checks"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.checks.get",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Reads article data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {
"articleId": "article_example"
},
"expected": "A response matching the published outputSchema for articles.checks.get."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleId": "article_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/articles/article_example/checks",
"body": null
},
"effects": "Reads article data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.checks.get",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/articles/*/checks",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "articles.bulk",
"title": "Run bulk article operation",
"description": "Apply one governed editorial operation to up to 100 selected articles.",
"method": "POST",
"path": "/api/articles/bulk",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"articleIds": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"operation": {
"type": "string",
"enum": [
"request_review",
"approve",
"publish",
"unpublish",
"delete"
]
}
},
"required": [
"articleIds",
"operation"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"articleId": {
"type": "string"
},
"success": {
"type": "boolean"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"articleId",
"success",
"error"
],
"additionalProperties": false
}
}
},
"required": [
"results"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.bulk",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"effects": [
"Changes article state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"articleIds": [
"article_example"
],
"operation": "request_review"
},
"expected": "A response matching the published outputSchema for articles.bulk."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"articleIds": [
"article_example"
],
"operation": "request_review"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/articles/bulk",
"body": {
"articleIds": [
"article_example"
],
"operation": "request_review"
}
},
"effects": "Changes article state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=articles.bulk",
"resource": {
"kind": "article",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/articles/bulk",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "templates.list",
"title": "List article templates",
"description": "List reusable article templates in the selected editorial workspace.",
"method": "GET",
"path": "/api/templates",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"templates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"titlePattern": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"name",
"description",
"titlePattern",
"excerpt",
"body",
"tags",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
}
},
"required": [
"templates"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=templates.list",
"resource": {
"kind": "article_template",
"idPath": "$.items[].id"
},
"effects": [
"Reads article template data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for templates.list."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/templates",
"body": null
},
"effects": "Reads article template data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=templates.list",
"resource": {
"kind": "article_template",
"idPath": "$.items[].id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/templates",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "templates.create",
"title": "Create article template",
"description": "Create a reusable article structure for the selected editorial workspace.",
"method": "POST",
"path": "/api/templates",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"description": {
"type": "string",
"maxLength": 320
},
"titlePattern": {
"type": "string",
"maxLength": 160
},
"excerpt": {
"type": "string",
"maxLength": 320
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"maxItems": 12,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 48
}
}
},
"required": [
"name"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"template": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"titlePattern": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"body": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "paragraph"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "heading"
},
"level": {
"anyOf": [
{
"type": "number",
"const": 2
},
{
"type": "number",
"const": 3
}
],
"description": "Section level. The article title renders as the H1, so body headings start at 2."
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"level",
"text"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "list"
},
"style": {
"type": "string",
"enum": [
"ordered",
"unordered"
]
},
"items": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
}
},
"required": [
"type",
"style",
"items"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "image"
},
"assetId": {
"type": "string",
"minLength": 1,
"description": "Blog media asset id. Upload the image first with media.upload; its response provides assetId and url."
},
"url": {
"type": "string",
"format": "uri"
},
"altText": {
"type": "string",
"maxLength": 320
},
"caption": {
"type": "string",
"maxLength": 320,
"description": "Rendered verbatim below the image; inline markdown is NOT applied here."
}
},
"required": [
"type",
"assetId",
"url",
"altText",
"caption"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "quote"
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
},
"attribution": {
"type": "string",
"maxLength": 160
}
},
"required": [
"type",
"text",
"attribution"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "divider"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "code"
},
"language": {
"type": "string",
"maxLength": 48
},
"code": {
"type": "string",
"minLength": 1
}
},
"required": [
"type",
"language",
"code"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "callout"
},
"tone": {
"type": "string",
"enum": [
"info",
"success",
"warning"
]
},
"title": {
"type": "string",
"maxLength": 120
},
"text": {
"type": "string",
"minLength": 1,
"description": "Plain text with optional inline markdown: **bold**, *italic*, `code`, and [label](https://…) links. No other markdown is rendered."
}
},
"required": [
"type",
"tone",
"title",
"text"
],
"additionalProperties": false
}
],
"description": "One typed content block. An article body is an ordered array of these blocks — paragraph, heading (levels 2–3), list, image, quote, divider, code, and callout."
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"name",
"description",
"titlePattern",
"excerpt",
"body",
"tags",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"template"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=templates.create",
"resource": {
"kind": "article_template",
"idPath": "$.id"
},
"effects": [
"Changes article template state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"name": "Product announcement",
"body": [
{
"type": "paragraph",
"text": "Opening."
}
]
},
"expected": "A response matching the published outputSchema for templates.create."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"name": "Product announcement",
"body": [
{
"type": "paragraph",
"text": "Opening."
}
]
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/templates",
"body": {
"name": "Product announcement",
"body": [
{
"type": "paragraph",
"text": "Opening."
}
]
}
},
"effects": "Changes article template state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=templates.create",
"resource": {
"kind": "article_template",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/templates",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "templates.delete",
"title": "Delete article template",
"description": "Delete a reusable article template.",
"method": "DELETE",
"path": "/api/templates/{templateId}",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"templateId": {
"type": "string",
"minLength": 1
}
},
"required": [
"templateId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"deleted": {
"type": "boolean",
"const": true
},
"templateId": {
"type": "string"
}
},
"required": [
"deleted",
"templateId"
],
"additionalProperties": false
},
"target": "api",
"destructive": true,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=templates.delete",
"resource": {
"kind": "article_template",
"idPath": "$.id"
},
"effects": [
"Changes article template state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"templateId": "template_example"
},
"expected": "A response matching the published outputSchema for templates.delete."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"templateId": "template_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "DELETE",
"path": "/api/templates/template_example",
"body": null
},
"effects": "Changes article template state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=templates.delete",
"resource": {
"kind": "article_template",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "declared_unserved",
"route_key": "DELETE /api/templates/*",
"evidence": "No matching served route was extracted from canonical staging source."
}
},
{
"name": "saved_searches.list",
"title": "List saved article searches",
"description": "List saved article search and sorting configurations.",
"method": "GET",
"path": "/api/saved-searches",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"searches": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"query": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"all",
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"all",
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"sort": {
"type": "string",
"enum": [
"updatedAt",
"title",
"publishedAt"
]
},
"order": {
"type": "string",
"enum": [
"asc",
"desc"
]
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"name",
"query",
"status",
"reviewStatus",
"sort",
"order",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
}
},
"required": [
"searches"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=saved_searches.list",
"resource": {
"kind": "saved_search",
"idPath": "$.items[].id"
},
"effects": [
"Reads saved search data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for saved_searches.list."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/saved-searches",
"body": null
},
"effects": "Reads saved search data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=saved_searches.list",
"resource": {
"kind": "saved_search",
"idPath": "$.items[].id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/saved-searches",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "saved_searches.create",
"title": "Create saved article search",
"description": "Save an article query, workflow filter, and sort order.",
"method": "POST",
"path": "/api/saved-searches",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"query": {
"type": "string",
"maxLength": 160
},
"status": {
"type": "string",
"enum": [
"all",
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"all",
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"sort": {
"type": "string",
"enum": [
"updatedAt",
"title",
"publishedAt"
]
},
"order": {
"type": "string",
"enum": [
"asc",
"desc"
]
}
},
"required": [
"name"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"search": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"query": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"all",
"draft",
"scheduled",
"published"
]
},
"reviewStatus": {
"type": "string",
"enum": [
"all",
"draft",
"in_review",
"changes_requested",
"approved"
]
},
"sort": {
"type": "string",
"enum": [
"updatedAt",
"title",
"publishedAt"
]
},
"order": {
"type": "string",
"enum": [
"asc",
"desc"
]
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"name",
"query",
"status",
"reviewStatus",
"sort",
"order",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"search"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=saved_searches.create",
"resource": {
"kind": "saved_search",
"idPath": "$.id"
},
"effects": [
"Changes saved search state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"name": "Needs approval",
"reviewStatus": "in_review"
},
"expected": "A response matching the published outputSchema for saved_searches.create."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"name": "Needs approval",
"reviewStatus": "in_review"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/saved-searches",
"body": {
"name": "Needs approval",
"reviewStatus": "in_review"
}
},
"effects": "Changes saved search state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=saved_searches.create",
"resource": {
"kind": "saved_search",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/saved-searches",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "saved_searches.delete",
"title": "Delete saved article search",
"description": "Delete a saved article search configuration.",
"method": "DELETE",
"path": "/api/saved-searches/{searchId}",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"searchId": {
"type": "string",
"minLength": 1
}
},
"required": [
"searchId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"deleted": {
"type": "boolean",
"const": true
},
"searchId": {
"type": "string"
}
},
"required": [
"deleted",
"searchId"
],
"additionalProperties": false
},
"target": "api",
"destructive": true,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=saved_searches.delete",
"resource": {
"kind": "saved_search",
"idPath": "$.id"
},
"effects": [
"Changes saved search state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"searchId": "search_example"
},
"expected": "A response matching the published outputSchema for saved_searches.delete."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"searchId": "search_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "DELETE",
"path": "/api/saved-searches/search_example",
"body": null
},
"effects": "Changes saved search state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=saved_searches.delete",
"resource": {
"kind": "saved_search",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "declared_unserved",
"route_key": "DELETE /api/saved-searches/*",
"evidence": "No matching served route was extracted from canonical staging source."
}
},
{
"name": "publications.list",
"title": "List publications",
"description": "List configured publishing destinations for the selected workspace.",
"method": "GET",
"path": "/api/publications",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"publications": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"baseUrl": {
"type": "string"
},
"description": {
"type": "string"
},
"defaultSeoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"defaultSeoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"isDefault": {
"type": "boolean"
},
"articleCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"name",
"slug",
"baseUrl",
"description",
"defaultSeoTitle",
"defaultSeoDescription",
"isDefault",
"articleCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
}
},
"required": [
"publications"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.list",
"resource": {
"kind": "publication",
"idPath": "$.items[].id"
},
"effects": [
"Reads publication data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for publications.list."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/publications",
"body": null
},
"effects": "Reads publication data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.list",
"resource": {
"kind": "publication",
"idPath": "$.items[].id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/publications",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "publications.create",
"title": "Create publication",
"description": "Create a named publishing destination with a canonical base URL.",
"method": "POST",
"path": "/api/publications",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"baseUrl": {
"type": "string",
"format": "uri"
},
"description": {
"type": "string",
"maxLength": 320
},
"defaultSeoTitle": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"defaultSeoDescription": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"slug": {
"type": "string",
"maxLength": 63
}
},
"required": [
"name",
"baseUrl"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"publication": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"baseUrl": {
"type": "string"
},
"description": {
"type": "string"
},
"defaultSeoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"defaultSeoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"isDefault": {
"type": "boolean"
},
"articleCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"name",
"slug",
"baseUrl",
"description",
"defaultSeoTitle",
"defaultSeoDescription",
"isDefault",
"articleCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"publication"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.create",
"resource": {
"kind": "publication",
"idPath": "$.id"
},
"effects": [
"Changes publication state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"name": "Company blog",
"baseUrl": "https://example.com/blog"
},
"expected": "A response matching the published outputSchema for publications.create."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"name": "Company blog",
"baseUrl": "https://example.com/blog"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/publications",
"body": {
"name": "Company blog",
"baseUrl": "https://example.com/blog"
}
},
"effects": "Changes publication state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.create",
"resource": {
"kind": "publication",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/publications",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "publications.update",
"title": "Update publication",
"description": "Update a publication name, destination, description, and SEO defaults.",
"method": "PATCH",
"path": "/api/publications/{publicationId}",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"publicationId": {
"type": "string",
"minLength": 1
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"baseUrl": {
"type": "string",
"format": "uri"
},
"description": {
"type": "string",
"maxLength": 320
},
"defaultSeoTitle": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
},
"defaultSeoDescription": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "null"
}
]
}
},
"required": [
"publicationId",
"name",
"baseUrl"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"publication": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"baseUrl": {
"type": "string"
},
"description": {
"type": "string"
},
"defaultSeoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"defaultSeoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"isDefault": {
"type": "boolean"
},
"articleCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"name",
"slug",
"baseUrl",
"description",
"defaultSeoTitle",
"defaultSeoDescription",
"isDefault",
"articleCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"publication"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.update",
"resource": {
"kind": "publication",
"idPath": "$.id"
},
"effects": [
"Changes publication state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"publicationId": "publication_example",
"name": "Company blog",
"baseUrl": "https://example.com/blog"
},
"expected": "A response matching the published outputSchema for publications.update."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"publicationId": "publication_example",
"name": "Company blog",
"baseUrl": "https://example.com/blog"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "PATCH",
"path": "/api/publications/publication_example",
"body": {
"publicationId": "publication_example",
"name": "Company blog",
"baseUrl": "https://example.com/blog"
}
},
"effects": "Changes publication state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.update",
"resource": {
"kind": "publication",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "PATCH /api/publications/*",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "publications.default.set",
"title": "Set default publication",
"description": "Choose the publication used automatically for new articles.",
"method": "POST",
"path": "/api/publications/{publicationId}/default",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"publicationId": {
"type": "string",
"minLength": 1
}
},
"required": [
"publicationId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"publication": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organizationId": {
"type": "string"
},
"workspaceId": {
"type": "string"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"baseUrl": {
"type": "string"
},
"description": {
"type": "string"
},
"defaultSeoTitle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"defaultSeoDescription": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"isDefault": {
"type": "boolean"
},
"articleCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"organizationId",
"workspaceId",
"name",
"slug",
"baseUrl",
"description",
"defaultSeoTitle",
"defaultSeoDescription",
"isDefault",
"articleCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"publication"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.default.set",
"resource": {
"kind": "publication",
"idPath": "$.id"
},
"effects": [
"Changes publication state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"publicationId": "publication_example"
},
"expected": "A response matching the published outputSchema for publications.default.set."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"publicationId": "publication_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/publications/publication_example/default",
"body": {
"publicationId": "publication_example"
}
},
"effects": "Changes publication state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.default.set",
"resource": {
"kind": "publication",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/publications/*/default",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "publications.delete",
"title": "Delete publication",
"description": "Delete an unused non-default publication.",
"method": "DELETE",
"path": "/api/publications/{publicationId}",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"publicationId": {
"type": "string",
"minLength": 1
}
},
"required": [
"publicationId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"deleted": {
"type": "boolean",
"const": true
},
"publicationId": {
"type": "string"
}
},
"required": [
"deleted",
"publicationId"
],
"additionalProperties": false
},
"target": "api",
"destructive": true,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.delete",
"resource": {
"kind": "publication",
"idPath": "$.id"
},
"effects": [
"Changes publication state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"publicationId": "publication_example"
},
"expected": "A response matching the published outputSchema for publications.delete."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"publicationId": "publication_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "DELETE",
"path": "/api/publications/publication_example",
"body": null
},
"effects": "Changes publication state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=publications.delete",
"resource": {
"kind": "publication",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "DELETE /api/publications/*",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "media.list",
"title": "List media",
"description": "List reusable Blog media assets in the selected workspace.",
"method": "GET",
"path": "/api/media",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"assets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"fileName": {
"type": "string"
},
"contentType": {
"type": "string"
},
"byteSize": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"altText": {
"type": "string"
},
"url": {
"type": "string"
},
"usageCount": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"fileName",
"contentType",
"byteSize",
"altText",
"url",
"usageCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
}
},
"required": [
"assets"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=media.list",
"resource": {
"kind": "media_asset",
"idPath": "$.items[].id"
},
"effects": [
"Reads media asset data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for media.list."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/media",
"body": null
},
"effects": "Reads media asset data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=media.list",
"resource": {
"kind": "media_asset",
"idPath": "$.items[].id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/media",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "media.upload",
"title": "Upload media",
"description": "Upload a reusable image to the Blog media library. The response asset provides the assetId and url an article image block requires.",
"method": "POST",
"path": "/api/media",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"contentBase64": {
"type": "string",
"minLength": 1
},
"contentType": {
"type": "string",
"enum": [
"image/gif",
"image/jpeg",
"image/png",
"image/webp"
]
},
"fileName": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"altText": {
"type": "string",
"maxLength": 320
}
},
"required": [
"contentBase64",
"contentType",
"fileName"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"asset": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"fileName": {
"type": "string"
},
"contentType": {
"type": "string"
},
"byteSize": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"altText": {
"type": "string"
},
"url": {
"type": "string"
},
"usageCount": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"fileName",
"contentType",
"byteSize",
"altText",
"url",
"usageCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"asset"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=media.upload",
"resource": {
"kind": "media_asset",
"idPath": "$.id"
},
"effects": [
"Changes media asset state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"contentBase64": "iVBORw0KGgo=",
"contentType": "image/png",
"fileName": "example.png"
},
"expected": "A response matching the published outputSchema for media.upload."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata",
"nextActionIds": [
"app_topolo_blog.articles.create",
"app_topolo_blog.articles.update"
],
"upload": {
"profile": "inline-base64",
"contentField": "contentBase64",
"contentTypeField": "contentType",
"fileNameField": "fileName",
"maxBytes": 10485760,
"acceptedContentTypes": [
"image/gif",
"image/jpeg",
"image/png",
"image/webp"
]
}
},
"documentation": {
"example_input": {
"contentBase64": "iVBORw0KGgo=",
"contentType": "image/png",
"fileName": "example.png"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "POST",
"path": "/api/media",
"body": {
"contentBase64": "iVBORw0KGgo=",
"contentType": "image/png",
"fileName": "example.png"
}
},
"effects": "Changes media asset state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=media.upload",
"resource": {
"kind": "media_asset",
"idPath": "$.id"
},
"next_action_ids": [
"app_topolo_blog.articles.create",
"app_topolo_blog.articles.update"
],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "POST /api/media",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "media.update",
"title": "Update media",
"description": "Update alternative text for a Blog media asset.",
"method": "PATCH",
"path": "/api/media/{assetId}",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"assetId": {
"type": "string",
"minLength": 1
},
"altText": {
"type": "string",
"maxLength": 320
}
},
"required": [
"assetId",
"altText"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"asset": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"fileName": {
"type": "string"
},
"contentType": {
"type": "string"
},
"byteSize": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"altText": {
"type": "string"
},
"url": {
"type": "string"
},
"usageCount": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"createdAt": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"id",
"fileName",
"contentType",
"byteSize",
"altText",
"url",
"usageCount",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"asset"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=media.update",
"resource": {
"kind": "media_asset",
"idPath": "$.id"
},
"effects": [
"Changes media asset state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"assetId": "media_example",
"altText": "A useful description"
},
"expected": "A response matching the published outputSchema for media.update."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"assetId": "media_example",
"altText": "A useful description"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "PATCH",
"path": "/api/media/media_example",
"body": {
"assetId": "media_example",
"altText": "A useful description"
}
},
"effects": "Changes media asset state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=media.update",
"resource": {
"kind": "media_asset",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "PATCH /api/media/*",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "media.delete",
"title": "Delete media",
"description": "Permanently delete a Blog media asset.",
"method": "DELETE",
"path": "/api/media/{assetId}",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"assetId": {
"type": "string",
"minLength": 1
}
},
"required": [
"assetId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"deleted": {
"type": "boolean",
"const": true
},
"assetId": {
"type": "string"
}
},
"required": [
"deleted",
"assetId"
],
"additionalProperties": false
},
"target": "api",
"destructive": true,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=media.delete",
"resource": {
"kind": "media_asset",
"idPath": "$.id"
},
"effects": [
"Changes media asset state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"assetId": "media_example"
},
"expected": "A response matching the published outputSchema for media.delete."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"assetId": "media_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "DELETE",
"path": "/api/media/media_example",
"body": null
},
"effects": "Changes media asset state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=media.delete",
"resource": {
"kind": "media_asset",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "DELETE /api/media/*",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "settings.get",
"title": "Get editorial settings",
"description": "Get workspace-level editorial and SEO defaults.",
"method": "GET",
"path": "/api/settings",
"permission": "workspace:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"settings": {
"type": "object",
"properties": {
"editorialName": {
"type": "string"
},
"defaultAuthorName": {
"type": "string"
},
"defaultSeoTitle": {
"type": "string"
},
"defaultSeoDescription": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"editorialName",
"defaultAuthorName",
"defaultSeoTitle",
"defaultSeoDescription",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"settings"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=settings.get",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"effects": [
"Reads workspace data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {},
"expected": "A response matching the published outputSchema for settings.get."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/settings",
"body": null
},
"effects": "Reads workspace data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=settings.get",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/settings",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "settings.update",
"title": "Update editorial settings",
"description": "Update workspace-level editorial and SEO defaults.",
"method": "PUT",
"path": "/api/settings",
"permission": "workspace:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"editorialName": {
"type": "string",
"maxLength": 100
},
"defaultAuthorName": {
"type": "string",
"maxLength": 100
},
"defaultSeoTitle": {
"type": "string",
"maxLength": 160
},
"defaultSeoDescription": {
"type": "string",
"maxLength": 320
}
},
"required": [
"editorialName",
"defaultAuthorName",
"defaultSeoTitle",
"defaultSeoDescription"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"settings": {
"type": "object",
"properties": {
"editorialName": {
"type": "string"
},
"defaultAuthorName": {
"type": "string"
},
"defaultSeoTitle": {
"type": "string"
},
"defaultSeoDescription": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"editorialName",
"defaultAuthorName",
"defaultSeoTitle",
"defaultSeoDescription",
"updatedAt"
],
"additionalProperties": false
}
},
"required": [
"settings"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=settings.update",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"effects": [
"Changes workspace state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission workspace:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"editorialName": "Editorial team",
"defaultAuthorName": "Topolo",
"defaultSeoTitle": "Company blog",
"defaultSeoDescription": "News and perspectives from the team."
},
"expected": "A response matching the published outputSchema for settings.update."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"editorialName": "Editorial team",
"defaultAuthorName": "Topolo",
"defaultSeoTitle": "Company blog",
"defaultSeoDescription": "News and perspectives from the team."
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "PUT",
"path": "/api/settings",
"body": {
"editorialName": "Editorial team",
"defaultAuthorName": "Topolo",
"defaultSeoTitle": "Company blog",
"defaultSeoDescription": "News and perspectives from the team."
}
},
"effects": "Changes workspace state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission workspace:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=settings.update",
"resource": {
"kind": "workspace",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "PUT /api/settings",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "organizations.data.export",
"title": "Export organization data",
"description": "Export all TopoloBlog articles and immutable revisions for the authenticated organization.",
"method": "GET",
"path": "/api/organizations/{organizationId}/data",
"permission": "privacy:read",
"authorizationMode": "static",
"readOnly": true,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"organizationId": {
"type": "string",
"minLength": 1
}
},
"required": [
"organizationId"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"organizationId": {
"type": "string"
},
"credentialsIncluded": {
"type": "boolean",
"const": false
},
"exportedAt": {
"type": "string"
},
"articles": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"workspace_id": {
"type": "string"
}
},
"required": [
"id",
"workspace_id"
],
"additionalProperties": {}
}
},
"revisions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"article_id": {
"type": "string"
}
},
"required": [
"id",
"article_id"
],
"additionalProperties": {}
}
}
},
"required": [
"organizationId",
"credentialsIncluded",
"exportedAt",
"articles",
"revisions"
],
"additionalProperties": false
}
},
"required": [
"data"
],
"additionalProperties": false
},
"target": "api",
"destructive": false,
"requiresConfirmation": false,
"agentAccess": "auto",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=organizations.data.export",
"resource": {
"kind": "organization",
"idPath": "$.id"
},
"effects": [
"Reads organization data without changing service state."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission privacy:read and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
}
],
"verify": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"examples": [
{
"input": {
"organizationId": "organization_example"
},
"expected": "A response matching the published outputSchema for organizations.data.export."
}
],
"recovery": {
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"organizationId": "organization_example"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --json"
],
"http_example": {
"method": "GET",
"path": "/api/organizations/organization_example/data",
"body": null
},
"effects": "Reads organization data without changing service state.",
"verification": [
"Validate the response against outputSchema and confirm it belongs to the selected resource context."
],
"recovery": [
{
"mode": "not_applicable",
"instructions": "This action does not change service state."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission privacy:read and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=organizations.data.export",
"resource": {
"kind": "organization",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "GET /api/organizations/*/data",
"evidence": "Matched to a served route extracted from canonical staging source."
}
},
{
"name": "organizations.data.erase",
"title": "Erase organization data",
"description": "Erase all TopoloBlog articles and revisions for the authenticated organization after literal ERASE confirmation.",
"method": "DELETE",
"path": "/api/organizations/{organizationId}/data",
"permission": "privacy:write",
"authorizationMode": "static",
"readOnly": false,
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"organizationId": {
"type": "string",
"minLength": 1
},
"confirmation": {
"type": "string",
"const": "ERASE"
}
},
"required": [
"organizationId",
"confirmation"
],
"additionalProperties": false
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"organizationId": {
"type": "string"
},
"erased": {
"type": "boolean",
"const": true
}
},
"required": [
"organizationId",
"erased"
],
"additionalProperties": false
}
},
"required": [
"data"
],
"additionalProperties": false
},
"target": "api",
"destructive": true,
"requiresConfirmation": true,
"agentAccess": "confirm",
"agentContract": {
"docsUrl": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=organizations.data.erase",
"resource": {
"kind": "organization",
"idPath": "$.id"
},
"effects": [
"Changes organization state in the selected Topolo resource context."
],
"errors": [
{
"status": 401,
"code": "authentication_required",
"recovery": "Authenticate again or provide a valid Topolo API key."
},
{
"status": 403,
"code": "permission_denied",
"recovery": "Grant the credential permission privacy:write and the required resource binding."
},
{
"status": 429,
"code": "rate_limited",
"recovery": "Wait for Retry-After when present, then retry without parallel duplicate calls."
},
{
"status": 422,
"code": "invalid_input",
"recovery": "Correct the payload using inputSchema, then validate before retrying."
},
{
"status": 503,
"code": "dependency_unavailable",
"recovery": "Retry the action. If it continues, inspect the structured error details using the request ID."
},
{
"status": 409,
"code": "state_conflict",
"recovery": "Read the current resource state, reconcile the intended change, and retry only if still valid."
}
],
"verify": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"examples": [
{
"input": {
"organizationId": "organization_example",
"confirmation": "ERASE"
},
"expected": "A response matching the published outputSchema for organizations.data.erase."
}
],
"recovery": {
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"contractSource": "derived-action-metadata"
},
"documentation": {
"example_input": {
"organizationId": "organization_example",
"confirmation": "ERASE"
},
"cli_example": [
"topolo actions --service topolo-blog --json",
"topolo actions get <action-id> --json",
"topolo actions validate <action-id> --data @payload.json --json",
"topolo actions plan <action-id> --data @payload.json --json",
"topolo actions call <action-id> --data @payload.json --confirm --json"
],
"http_example": {
"method": "DELETE",
"path": "/api/organizations/organization_example/data",
"body": null
},
"effects": "Changes organization state in the selected Topolo resource context.",
"verification": [
"Validate the response against outputSchema and re-read the affected resource to confirm the intended state."
],
"recovery": [
{
"mode": "irreversible",
"instructions": "No safe automatic inverse is published. Confirm the change and retain any required export or snapshot before calling."
},
"401 authentication_required: Authenticate again or provide a valid Topolo API key.",
"403 permission_denied: Grant the credential permission privacy:write and the required resource binding.",
"429 rate_limited: Wait for Retry-After when present, then retry without parallel duplicate calls.",
"422 invalid_input: Correct the payload using inputSchema, then validate before retrying.",
"503 dependency_unavailable: Retry the action. If it continues, inspect the structured error details using the request ID.",
"409 state_conflict: Read the current resource state, reconcile the intended change, and retry only if still valid."
],
"docs_url": "https://docs.topolo.app/reference/actions?service=topolo-blog&action=organizations.data.erase",
"resource": {
"kind": "organization",
"idPath": "$.id"
},
"next_action_ids": [],
"rollback_action_id": null
},
"implementation": {
"status": "implemented",
"route_key": "DELETE /api/organizations/*/data",
"evidence": "Matched to a served route extracted from canonical staging source."
}
}
],
"action_coverage": {
"status": "ok",
"served_routes": 44,
"matched_actions": 37,
"declared_unserved_actions": [
"DELETE /api/saved-searches/*",
"DELETE /api/templates/*",
"POST /api/articles/*/review/approve",
"POST /api/articles/*/review/changes-requested",
"POST /api/articles/*/review/request"
],
"coverage_excluded_actions": [],
"uncatalogued_routes": [
{
"key": "DELETE /api/saved-searches",
"method": "DELETE",
"path": "/api/saved-searches",
"source": "apps/api/src/editorial-routes.ts",
"target": "api"
},
{
"key": "DELETE /api/templates",
"method": "DELETE",
"path": "/api/templates",
"source": "apps/api/src/editorial-routes.ts",
"target": "api"
},
{
"key": "GET /api/public/publications",
"method": "GET",
"path": "/api/public/publications",
"source": "apps/api/src/article-routes.ts",
"target": "api"
},
{
"key": "GET /api/public/publications/*/*",
"method": "GET",
"path": "/api/public/publications/{segment1}/{segment2}",
"source": "apps/api/src/article-routes.ts",
"target": "api"
},
{
"key": "POST /api/articles/*/review",
"method": "POST",
"path": "/api/articles/{segment1}/review",
"source": "apps/api/src/article-routes.ts",
"target": "api"
}
],
"ignored_routes": 2,
"configured_exclusions": 3,
"configuration_findings": [
"GET /api/public/media/*: exclusion matches no served route",
"GET /api/public/publications/*/articles: exclusion matches no served route",
"GET /api/public/publications/*/articles/*: exclusion matches no served route"
],
"notes": []
},
"runtime_contract_audit": {
"status": "verified",
"actions": 42,
"contracts": 42,
"contract_module": "topolo.action-contracts.mjs",
"validator_sources": [
"apps/api/src/worker.ts"
],
"authorization_sources": [
"apps/api/src/worker.ts"
],
"findings": []
}
}
],
"mobile_contracts": [],
"package_manifests": [],
"deployment_configs": [],
"source_signals": {
"api_routes": [
{
"method": "ALL",
"path": "*",
"source_path": "apps/TopoloBlog/apps/api/src/worker.ts"
},
{
"method": "LITERAL",
"path": "/api/health",
"source_path": "apps/TopoloBlog/apps/api/src/worker.ts"
},
{
"method": "LITERAL",
"path": "/api/app-identity",
"source_path": "apps/TopoloBlog/apps/api/src/worker.ts"
},
{
"method": "LITERAL",
"path": "/api/widget",
"source_path": "apps/TopoloBlog/apps/api/src/worker.ts"
},
{
"method": "LITERAL",
"path": "/api/bootstrap",
"source_path": "apps/TopoloBlog/apps/api/src/worker.ts"
}
],
"ui_routes": [
{
"path": "/getting-started",
"source_path": "apps/TopoloBlog/apps/web/src/App.tsx"
},
{
"path": "/articles",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/calendar",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/media",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/templates",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/publications",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/analytics",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/settings",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/settings/:section",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/articles/:articleId",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/getting-started",
"source_path": "apps/TopoloBlog/apps/web/src/app-routes.tsx"
},
{
"path": "/blog/identity-is-operating-infrastructure",
"source_path": "apps/TopoloBlog/apps/web/src/routes/AnalyticsRoute.tsx"
}
],
"test_cases": [],
"database_tables": []
},
"documentation": {
"declared_paths": [
"internal/apps/blog",
"applications/blog"
],
"present_paths": [
"internal/apps/blog",
"applications/blog"
],
"missing_paths": [],
"human_reference": "/systems/topolo-blog",
"machine_reference": "/machine/systems/topolo-blog.json",
"action_examples": 42,
"action_schemas": 42
},
"source_findings": [
{
"type": "declared_unserved_actions",
"source_path": "apps/TopoloBlog/topolo.app.json",
"detail": [
"DELETE /api/saved-searches/*",
"DELETE /api/templates/*",
"POST /api/articles/*/review/approve",
"POST /api/articles/*/review/changes-requested",
"POST /api/articles/*/review/request"
]
},
{
"type": "uncatalogued_routes",
"source_path": "apps/TopoloBlog/topolo.app.json",
"detail": [
{
"key": "DELETE /api/saved-searches",
"method": "DELETE",
"path": "/api/saved-searches",
"source": "apps/api/src/editorial-routes.ts",
"target": "api"
},
{
"key": "DELETE /api/templates",
"method": "DELETE",
"path": "/api/templates",
"source": "apps/api/src/editorial-routes.ts",
"target": "api"
},
{
"key": "GET /api/public/publications",
"method": "GET",
"path": "/api/public/publications",
"source": "apps/api/src/article-routes.ts",
"target": "api"
},
{
"key": "GET /api/public/publications/*/*",
"method": "GET",
"path": "/api/public/publications/{segment1}/{segment2}",
"source": "apps/api/src/article-routes.ts",
"target": "api"
},
{
"key": "POST /api/articles/*/review",
"method": "POST",
"path": "/api/articles/{segment1}/review",
"source": "apps/api/src/article-routes.ts",
"target": "api"
}
]
},
{
"type": "action_coverage_configuration",
"source_path": "apps/TopoloBlog/topolo.app.json",
"detail": [
"GET /api/public/media/*: exclusion matches no served route",
"GET /api/public/publications/*/articles: exclusion matches no served route",
"GET /api/public/publications/*/articles/*: exclusion matches no served route"
]
}
]
}