content_post_apply
Create or manage source-supported content in the exact installed app.
Read the shared content contract for authorization, app identity, result interpretation and recovery.
Inputs and actions
Require channelCode, pAppCode, requestId and expectedRevision; dryRun defaults to false. Copy selectionRevision from content_posts_get list for create/save_outlink, or revision from detail for ordinary existing-post actions. The article_conversion_link extension below requires its dedicated link-view revision; article_assignee requires its dedicated current-assignee/candidate revision. requestId accepts 8–80 ASCII letters, digits, _ or -. Unsupported object fields are rejected.
| action.kind | Action fields and scope |
|---|---|
| create | fields and explicit isPublished; notices, free boards, articles, Timeline PLAIN/IMAGE/YOUTUBE stories, photobooks and resources. Resource creation must be unpublished. |
| update | postId and a nonempty partial fields object for the same editors; existing question text is also editable. |
| set_article_category | Existing B00001/B9xx01 postId, published categoryId, complete labelIds and expectedTaxonomyRevision; see the separate two-revision contract below. |
| set_article_labels | Existing B00001/B9xx01 postId, zero to five unique GENERAL labelIds and expectedLabelsRevision; requires the common label read hook. |
| set_article_image_description | Existing B00001/B9xx01 postId and one nonempty imageDescription for both images; see the preservation and restoration limits below. |
| set_article_slug | Original B00001 OWNER only, postId, slug custom/keep and confirmation CHANGE_ARTICLE_SLUG; see below. |
| timeline_video_create | A00001/A9xx01 OWNER; acknowledged uploadTaskId, dedicated creation revision, content, isPublished, labels/catalog choices and CREATE_TIMELINE_VIDEO. Creates an encoding candidate only; see the asynchronous workflow below. |
| visibility | postId and isPublished; timeline, notice, free board, question, article, photobook and resource apps. |
| delete | postId and confirmation DELETE_POST; all visibility families plus inquiries. Permanent, with no undo. |
| save_outlink | Complete fields for B00002; appends a new published history entry, never edits an older one. |
| update_welcome | Existing current welcome postId and nonempty fields for B00006; creation is unsupported. |
| article_conversion_link | Later B00001-only extension: postId and operation initialize/edit with the matching confirmation; see below. |
| article_assignee | Original B00001 OWNER only: postId, discovered profileId and confirmation CHANGE_ARTICLE_ASSIGNEE; see the candidate and recovery contract below. |
Editor fields
Lengths below are UTF-16 units. Serialized HTML bounds are conservative bridge guards, not proof of visible-character or rich-editor equivalence. Omitted update fields are preserved. publishedAt, where accepted, is source UTC metadata in YYYY-MM-DDTHH:mm:ss form; it does not schedule publication.
| Family | Fields and bounds |
|---|---|
| A00001 / A9xx01 timeline | content 2–20000; create supports PLAIN (default), IMAGE with 1–10 existing imageSrcs, or a source-supported YOUTUBE link. Creation does not accept publishedAt. Updates retain existing media; publishedAt is supported only for PLAIN. Optional timelineSelection requires current GENERAL label IDs and revision. VIDEO uses the separate candidate action below. |
| A00002 notice | title 2–200, content 2–60000; optional uploadFileSrc (URL or null), publishedAt. |
| A00003 free board | title 2–200, content 2–20000, discovered boardCategoryId; optional boardCategoryLabelIds (zero or one), uploadFileSrcs (up to 100), publishedAt. Existing edits/pins retain the category and verify retained labels; cross-category moves are unsupported. |
| A00009 question | Update content 2–5000. Starting a question requires its separate workflow. |
| B00001 article | title 1–100, content 2–50000; optional publishedAt, thumbnailSrc and coverImageSrc (URL or empty string to clear). |
| B00005 photobook | title 1–50; content is optional, empty, or 2–50000. Optional introduction 0–120, publishedAt, nonnegative integer contentRatingsAge and storyResource. Creation requires storyResource; blank create text is omitted, while explicit empty update text clears it. |
| B00012 resource | title 1–200; optional content 0–5000, introduction 0–200, publishedAt, contentRatingsAge, thumbnailSrc and coverImageSrc. Creation requires one uploadFileSrc plus thumbnailSrc, with isPublished:false. Update uses a complete uploadFileSrcs list of 1–10 retained URLs, never the singular create field. |
| B00002 outlink | title 1–100, conversionBtnText 1–20, conversionLink and contentImageSrc URLs. |
| B00006 welcome | Optional title 1–200, content 0–3000, footer 0–200, imageUrl (URL or null), youtubeUrl (URL or empty), and up to three links. Each link has kind WEB_LINK/INTERNAL_LINK, label 0–20 without ] or line breaks, and url. Internal links must identify this channel. Image and YouTube are mutually exclusive; explicitly clear the previous media when switching. |
Photobook storyResource has type IMAGE, 1–50 ordered imageSrcs, equally many audioSrcs (URL or NOT_CONNECT) and audioUse. Any audio requires already available Z00006. No installation or purchase is performed. URLs use HTTP(S), have no embedded credentials and are bounded to 4096 characters. content_file_upload supplies supported uploaded URLs; it is separate from this save.
Results and recovery
Fresh success returns CONTENT_POST_SAVED or CONTENT_POST_DELETED, taskId, post (null after deletion), revision and stored readback/preservation indicators. Deletion observes the exact detail missing; it is not a complete backup, restoration or orphan-resource cleanup. Visibility changes can alter publishedAt. Unknown fields retained by the source snapshot are compared except the documented reaction/counter/timestamp exclusions.
Use taskType content-post. A prepared task can continue with its original input; sent writes are read back without resending. Creation with no trustworthy returned post ID yields CONTENT_CREATE_ID_UNKNOWN and requires console reconciliation, never a title/content match. Completed replay is historical. No atomic conditional write or automatic rollback is available. Use content_schedule_apply for future publication and content_series_apply for collections. Pricing, notifications and unsupported rich-media editors are outside this contract.
Input example
This is an input illustration, not a recorded call. Replace the channel, app, observed IDs and all-zero revision with values from the matching authorized read. A dry run does not save changes.
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "example-request-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "update",
"postId": 1,
"fields": {
"title": "Updated article title"
}
}
}
Select an existing article category
It reuses content-post, the existing post transport and taxonomy discovery; it does not add a tool or depend on the separate pending catalog-membership port.
Read the post detail and use its revision as top-level expectedRevision. Discover categories with content_taxonomy_get, choose an existing published category, then copy that category detail's revision into action.expectedTaxonomyRevision. Both revisions are 64-character lowercase hex values from different snapshots; neither substitutes for the other.
The action also requires positive safe integer postId/categoryId and labelIds: the complete desired array of zero to five distinct subcategory IDs belonging to that category. An empty array clears subcategories. Switching categories never carries prior subcategory IDs implicitly. Category removal/null semantics, assignment during post creation, general labels, SEO, category publication and category-cover upload remain outside this action. Newly created unpublished categories are ineligible.
Preflight requires matching current post state, complete category inventory/detail/subcategories and taxonomy revision, plus the separate published-category filter agreeing with the selected detail. Unknown/foreign IDs, missing/incomplete reads, unsupported apps or stale revisions stop the save. The one post PUT contains only boardCategoryId and boardCategoryLabelIds under the exact installed consumer; it does not publish the post or change notifications.
Readback requires the requested category/subcategory identities and array and fresh category eligibility, with unrelated body, visibility, general labels, SEO, access/pricing references and other retained post fields preserved. Existing interaction-counter/updatedAt exclusions apply. Category post counts can legitimately change, so the preflight taxonomy revision is not an after-write equality test. This post readback does not independently establish taxonomy metadata preservation or effective visitor access.
The sent boundary is durable before PUT. Repeating the exact sent input or task_resume only reads back; saved success is historical. This workflow has no global prohibition on a different requestId, so reconcile uncertain work and read fresh state before planning another edit. No atomic upstream revision check, title-based inference, automatic rollback or original-ID restoration is promised.
Illustrative plan clearing subcategories while selecting an eligible published category. Replace both observed IDs and both revisions:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-category-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"action": {
"kind": "set_article_category",
"postId": 7,
"categoryId": 3,
"labelIds": [],
"expectedTaxonomyRevision": "0000000000000000000000000000000000000000000000000000000000000000"
},
"dryRun": true
}
Article image descriptions
It reuses the registered post transport and content-post recovery. Read the exact post detail with content_posts_get and use its revision as expectedRevision. Require action.postId and imageDescription, a string of 1–100 UTF-16 units; it is not trimmed. The one value becomes both postMeta.thumbnailAltText and postMeta.coverAltText, matching the original editor.
Separate descriptions and empty/null clearing are unsupported. The action accepts no image URL/file, publication, category, pricing or notification fields. It does not upload images, edit the slug or expose general search/OG metadata. dryRun validates without the post PUT.
The source editor resubmits the existing slug after removing its post-ID suffix. The bridge permits an unambiguous trailing suffix, retains a nonempty slug with no matching ID fragment, and omits empty/null/missing slug. A matching fragment in the middle, repeated fragments or a suffix-only slug yields ARTICLE_SLUG_UNVERIFIED before dispatch. Invalid metadata or a non-string non-null slug yields ARTICLE_METADATA_UNVERIFIED. Do not supply a guessed replacement address.
Readback must retain the original returned slug verbatim, even when the request stripped its suffix, and preserve image URLs, all unselected metadata including unknown nested properties, and unrelated post fields under the existing preservation rules. A bare/changed returned slug, lost metadata or mismatched description remains uncertain.
The sent boundary precedes PUT. Exact retry or task_resume after sending only reads back; it never repeats the PUT. Completed results are historical. The existing workflow does not globally prevent another requestId after uncertainty, so reconcile the original task and obtain a fresh read before another edit.
Exact restoration through this shared input is possible only when both original descriptions were identical and nonempty. Missing, empty or asymmetric originals cannot be claimed restorable here. Any later restoration needs those original values, a fresh revision and a new request; no automatic rollback exists. Actual API behavior, console comparison, visitor accessibility and restoration remain unverified.
Illustrative dry run for an observed existing article; replace the ID and revision:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-image-description-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "set_article_image_description",
"postId": 7,
"imageDescription": "A notebook on a wooden desk"
}
}
Replace an article's GENERAL label selection
Read the GENERAL inventory and post detail. Supply the post revision as expectedRevision and the inventory revision as action.expectedLabelsRevision; both are separate 64-character lowercase hex values. The action requires positive safe integer postId and the complete desired labelIds set: zero to five unique, existing GENERAL IDs. An empty array clears this post's selection without deleting label records. Category sublabels are ineligible and selection order is not a requested sort order.
Stale post/inventory revisions, unknown or duplicate IDs and unsupported families stop the save. The exact installed consumer scopes one post PUT containing only labelIds. Readback must match the selected ID set and a fresh complete GENERAL inventory while preserving unrelated content, category/subcategory selection, visibility, image URLs, metadata and access/pricing references under the existing post preservation rules. Usage counts can change, so the preflight inventory revision is not an after-write equality assertion. This readback does not independently measure label metadata or other posts' selections.
The existing content-post journal applies: dryRun validates without writing, sent retry/task_resume only reads back, and completed replay is historical. Missing read transport during recovery, mismatched labels or unrelated drift remains uncertain. No automatic rollback or request-ID-wide lock is added; reconcile the original task and read fresh state before another request. Assignment during post creation, label lifecycle, category selection and series assignment remain separate.
Fresh post/inventory revisions, one complete-selection PUT, unrelated-field preservation and readback-only sent recovery remain required. Older hosts without the hook still return CONTENT_GENERAL_LABEL_TRANSPORT_REQUIRED before a write. Original-console/visitor comparison, actual restoration and hosted/LLM behavior remain unverified.
Illustrative dry run clearing a post's GENERAL selection; replace the post ID and both revisions:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-general-labels-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "set_article_labels",
"postId": 7,
"labelIds": [],
"expectedLabelsRevision": "0000000000000000000000000000000000000000000000000000000000000000"
}
}
Create an article with category and GENERAL labels
Optional action.articleSelection selects an existing published category, GENERAL labels, or both in the same post creation. Place it beside fields and isPublished, not inside fields. It is not accepted on update and is rejected for other app families. Omitting articleSelection preserves the previous creation payload, defaults and task fingerprint.
The selection object must contain category, generalLabels, or both. Each supplied object has its own required expectedRevision; all revisions are 64-character lowercase hex values copied from their corresponding reads.
| Input | Required discovery and value |
|---|---|
| Top-level expectedRevision | selectionRevision from this app's post list; it binds the creation context, not the complete post inventory. |
| articleSelection.category | categoryId, labelIds and expectedRevision from the selected category detail. categoryId must identify an existing published category. labelIds contains zero to five unique subcategory IDs belonging to it, in the requested order. |
| articleSelection.generalLabels | labelIds and expectedRevision from GENERAL inventory discovery. Supply zero to five unique GENERAL IDs; order is not a requested label order. |
All IDs are positive safe integers. Category and GENERAL IDs are separate namespaces. Category eligibility requires complete inventory/detail/subcategory reads and agreement with the published-category filter. Stale revisions, missing/inconsistent reads, unpublished categories and unknown or foreign IDs stop creation. dryRun performs these checks without creating a post.
One POST to the existing source post endpoint carries ordinary content, author and visibility fields, plus boardCategoryId when selected and each nonempty selected label array. Empty boardCategoryLabelIds and labelIds arrays are omitted from the POST, matching the original creation form; an explicitly requested empty selection must still read back empty. An omitted selection object imposes no new selection assertion. This option neither creates category/label records nor publishes a category, and does not send a second PUT to attach selections.
Success uses CONTENT_POST_SAVED with the response-returned post ID, fresh post detail and fresh selected inventories. Readback checks category identity, subcategory IDs and order, the GENERAL ID set, requested content/images/visibility and author fields. Legitimate usage-count changes are allowed; preflight inventory revisions are not after-write equality tests. Missing labels, a category that becomes ineligible or mismatched fields leave the result uncertain.
The existing content-post journal persists the returned ID before readback. A known ID can be observed after readback failure. A lost or untrustworthy creation receipt never permits title-based adoption or another POST; retain the original request/task and reconcile it. Sent recovery only reads, completed replay is historical, and changed credentials or instance context block recovery. No automatic rollback or cleanup is provided.
The source's shared SDK fixture uses HttpPublPort with mocked HTTP. This option needs no new port, task type or public method and is independent of GENERAL lifecycle writes. The later articleSlug option below adds bounded custom addresses. General SEO editing, notification controls and unsupported inline media remain outside these options; publication scheduling stays separate.
Illustrative unpublished creation with both selections. Replace all IDs and all three revisions from their respective reads; dryRun saves nothing:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-create-selection-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "create",
"fields": {
"title": "Selected article",
"content": "Article content"
},
"isPublished": false,
"articleSelection": {
"category": {
"categoryId": 3,
"labelIds": [
11
],
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000"
},
"generalLabels": {
"labelIds": [
21,
22
],
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000"
}
}
}
}
Illustrative independent GENERAL selection with an explicit empty set. Category selection is omitted; replace both revisions:
{
"channelCode": "selected-channel",
"pAppCode": "B90101",
"requestId": "article-create-empty-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "create",
"fields": {
"title": "Selected article",
"content": "Article content"
},
"isPublished": false,
"articleSelection": {
"generalLabels": {
"labelIds": [],
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000"
}
}
}
}
Image description during article creation
It is one untrimmed string of 1–100 UTF-16 units applied to both thumbnail and cover. Supply it beside fields and isPublished. The description can be used without image URLs, or with existing thumbnailSrc/coverImageSrc in fields and articleSelection.
Top-level expectedRevision still comes from the post list's selectionRevision. Combining category or GENERAL selections also requires their separate revisions. Omitting articleImageDescription preserves the previous creation input, defaults, payload and task fingerprint. This image-description option accepts no empty/null clearing, separate descriptions or arbitrary postMeta input. A custom address can be composed through the later articleSlug option below. Other app families reject the option. For an existing article, use set_article_image_description; generic update does not accept this creation option.
Without articleSlug, the same single creation POST adds postMeta with slug:null and both thumbnailAltText and coverAltText set to the requested value. Null matches the original creation form's blank slug input. No upload or follow-up PUT occurs. It does not copy the existing-post editor's suffix-stripping behavior or promise how the server generates a URL.
Fresh readback requires a metadata object with both requested descriptions and all other requested fields, including content, visibility, image URLs and any selected category/labels. Without an explicit articleSlug option, a returned slug may be absent, string or null; a generated string is observed without asserting a normalization or suffix rule. An explicit articleSlug additionally requires the valid durable slug receipt and matching fresh read described below. Mismatched descriptions, malformed metadata or changed requested fields remain CONTENT_OUTCOME_UNVERIFIED. No corrective write is sent.
On matched readback, CONTENT_POST_SAVED includes verification.imageDescriptions:true, verification.slugPolicyVerified:false and verification.visitorAccessibility:false. Stored matching text does not prove visitor accessibility or the default URL policy. Creation retains verification.preservation:false because no earlier post exists. Existing-post image-description editing keeps its original-slug and unrelated-metadata preservation requirements.
The existing content-post task stores the returned post identity before readback. A durable ID permits observation after a read failure; lost creation identity never permits another POST or title-based adoption. Sent retry/resume only observes, completed replay is historical, and dryRun validates without creating a post. No new shared port, task type or tool is added.
Illustrative unpublished creation without selected images. Replace the context and list revision:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-create-description-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "create",
"fields": {
"title": "New article",
"content": "Article body"
},
"isPublished": false,
"articleImageDescription": "A notebook on a wooden desk"
}
}
Illustrative composition with existing image URLs and both taxonomy selections. Replace all URLs, IDs and the three revisions from authorized reads:
{
"channelCode": "selected-channel",
"pAppCode": "B90101",
"requestId": "article-create-combined-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "create",
"fields": {
"title": "New article",
"content": "Article body",
"thumbnailSrc": "https://example.invalid/thumbnail.png",
"coverImageSrc": "https://example.invalid/cover.png"
},
"isPublished": false,
"articleImageDescription": "A notebook on a wooden desk",
"articleSelection": {
"category": {
"categoryId": 3,
"labelIds": [
11
],
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000"
},
"generalLabels": {
"labelIds": [
21
],
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000"
}
}
}
}
Photobook optional text and explicit clearing
Nonempty content still requires 2–50,000 UTF-16 code units; the upper bound has not increased. A one-unit nonempty value is invalid. Title remains 1–50 units, introduction 0–120. Null input is not a clear operation. Other content families retain their own validators.
| Operation and field | Requested value | Body and verification |
|---|---|---|
| Create content or introduction | Omitted or empty string | Omit that field from the single POST. Fresh readback may be absent, null or empty; unexpected nonempty text leaves the outcome unverified. |
| Update content or introduction | Explicit empty string | Send that empty string in the PUT. Fresh readback must contain exactly empty text; null or an absent field does not confirm the clear. |
| Update content or introduction | Omitted | Do not send the field; verify that its prior value is preserved. An update still requires at least one supported field. |
| Create or update nonempty content | 2–50,000 UTF-16 units | Retain the existing content rules and exact requested-value verification. |
Creation still needs the title, explicit isPublished and storyResource with 1–50 ordered images and one matching audio URL or NOT_CONNECT slot per image. Sound changes still require the existing Z00006 check. Text-only edits preserve existing image/audio slots without resending them or requiring sound activation again. Omitted title, visibility, age rating, metadata, access references and other unchanged fields remain subject to the existing preservation check. This text correction adds no upload, activation, publication default or label write.
Use selectionRevision from the post list for create and the selected post's detail revision for update. The existing content-post task, request fingerprint, dry run, stale-revision and permission rules remain. Nonempty legacy inputs and saved fingerprints retain their contract. Prepared tasks are revalidated; once sent, recovery reads back without another POST/PUT. A lost create identity is never inferred from matching text or recreated. A null readback for an explicit update clear remains uncertain; do not send a corrective write to force a representation. Restoring earlier text is a separate authorized update after reconciliation and a fresh read, not an automatic rollback.
Label-name chips in post/series lists and a generic repository are insufficient evidence. Article category/GENERAL-label actions are not broadened to photobooks.
Illustrative dry-run inputs only. Replace the selected target, revision and existing image URL with authorized observed values. These examples do not upload a file, issue a live call or demonstrate a saved result.
Create without either text field:
{
"channelCode": "selected-channel",
"pAppCode": "B00005",
"requestId": "photobook-create-no-text",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "create",
"isPublished": false,
"fields": {
"title": "Photo collection",
"storyResource": {
"type": "IMAGE",
"imageSrcs": [
"https://example.invalid/existing-image.png"
],
"audioSrcs": [
"NOT_CONNECT"
],
"audioUse": false
}
}
}
}
Explicit empty text during creation has the same omitted-field payload semantics:
{
"channelCode": "selected-channel",
"pAppCode": "B00005",
"requestId": "photobook-create-empty-text",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "create",
"isPublished": false,
"fields": {
"title": "Photo collection",
"storyResource": {
"type": "IMAGE",
"imageSrcs": [
"https://example.invalid/existing-image.png"
],
"audioSrcs": [
"NOT_CONNECT"
],
"audioUse": false
},
"content": "",
"introduction": ""
}
}
}
Clear only an existing description while retaining its introduction and other fields:
{
"channelCode": "selected-channel",
"pAppCode": "B00005",
"requestId": "photobook-clear-description",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "update",
"postId": 50,
"fields": {
"content": ""
}
}
}
No new tool, task type, transport or runtime setting is added. The existing upload-storage limitation and recorded runtime boundary are unchanged.
Original article conversion initialization and editing
The dedicated reader describes its shared transport/navigation and integration boundary. Use OWNER on exact B00001; aliases, delegates and creators are outside this option. No new method or task type is added.
Require channelCode, pAppCode:B00001, requestId and expectedRevision from the article_conversion_link view. Retain the observed numeric postId and string distinctId separately. dryRun defaults to false; use true to inspect plannedBody and noop without a business write or new task. Choose one action:
| operation | Required action fields |
|---|---|
| initialize | kind:article_conversion_link, postId, confirmation:INITIALIZE_ARTICLE_CONVERSION_LINK. No changes object. The dedicated link must be absent. |
| edit | kind:article_conversion_link, postId, confirmation:CHANGE_ARTICLE_CONVERSION_LINK and nonempty changes. The dedicated link must exist. |
Editable fields and preservation
| changes field | Meaning and limits |
|---|---|
| title | Nonblank text, at most 40 UTF-16 units after trimming. |
| description | Up to 60 UTF-16 units after trimming; an empty string clears it. |
| linkType | INTERNAL_LINK or WEB_LINK. This is separate from the read-only BANNER/BUTTON presentation type. |
| destinationUrl | HTTP(S), at most 4096 characters, with no embedded credentials, whitespace or control characters. |
| enabled | Boolean; saved as the inverse isDisabled value. |
| clearThumbnail | Only true is accepted; clears thumbnailSrc. Omit it to preserve the existing thumbnail. |
At least one supported field must be supplied. Only caller-edited title/description are trimmed; omitted values retain their original whitespace. An edit sends the complete source form containing linkType, title, description, thumbnailSrc, destinationUrl and isDisabled, using current values for omitted fields. The resulting full form must satisfy all field limits. Initialization sends one empty-body POST; editing sends one PUT to the exact post's dedicated conversion-link route. No-op editing sends no PUT.
An INTERNAL_LINK destination must begin with the path segments /channels/{exact channelCode}. This is stricter than the original substring check. It verifies the selected channel path, not host ownership, destination reachability or visitor access. Changing to WEB_LINK is supported with a valid destination.
Arbitrary thumbnail replacement URLs and new thumbnail bytes are unsupported. Preserve or clear an existing thumbnail only. Clearing cannot restore the old image through this bounded API alone; an independently authorized original-console uploader is required. No uploader or image-size support is implied by these fields.
Readback preserves the dedicated link's distinctId, type, postId, insertedAt and unknown fields; only updatedAt is excluded from link equality. It also preserves the article's semantic fields under the existing post counter/reaction/updatedAt exclusions. The optional post.postConversionLink string/null projection remains part of that comparison. An unexplained change to it stays unresolved even if suspected to be server-derived. Readback is not causal proof, an atomic conditional write, original-console agreement or restoration.
Results, uncertainty and recovery
Successful fresh verification returns ARTICLE_CONVERSION_INITIALIZED or ARTICLE_CONVERSION_SAVED, taskId, taskType:content-post, conversionLink, initialized:true and a fresh dedicated revision. verification separates readback/preservation from atomicSnapshot, console, visitor and restoration. Store the original input and task ID.
The per-article pending guard and sent task are durably saved before an effect. An initialization receipt must contain the exact returned string identity and be durably stored before createdIdentityKnown can be true. A lost/malformed receipt or failure to save that identity cannot be repaired by guessing from the current link, title or matching fields. Never initialize again under a new request ID to bypass this uncertainty.
ARTICLE_CONVERSION_OUTCOME_UNVERIFIED retains the task, diagnostic and a historical before snapshot. For initialization it includes createdIdentityKnown. Its parent article link is an inspection destination with a next-step instruction, not confirmation of a saved link. Known-identity initialization and edits can reconcile through exact retry or task_resume, which only read back and never repeat POST/PUT. Unknown-identity initialization remains unresolved. No automatic rollback or thumbnail restoration occurs.
ARTICLE_CONVERSION_PENDING blocks new conversion writes and fresh ordinary post mutations on the same article while a prior conversion task is unresolved. History reads remain available. The guard shares the current post mutation lock; it does not migrate older ordinary-post journals or serialize external writers. Reusing a request ID with another action or journal kind yields REQUEST_ID_REUSED. Read the dedicated link again before a later authorized edit or attempted reverse change.
ARTICLE_CONVERSION_EXISTS requires editing the existing link; ARTICLE_CONVERSION_MISSING requires initialization first. CONTENT_CONFLICT requires a fresh dedicated read. Missing shared forwarding yields ARTICLE_CONVERSION_TRANSPORT_REQUIRED. The missing-installation versus missing-link distinction is described in the reader.
Illustrative plans only. Replace the authorized channel, observed post ID and all-zero revision from a fresh dedicated read. Preview initialization only when initialized:false:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-conversion-init-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "article_conversion_link",
"postId": 7,
"operation": "initialize",
"confirmation": "INITIALIZE_ARTICLE_CONVERSION_LINK"
}
}
Preview an existing link edit. Omitted thumbnail and other fields are preserved:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-conversion-edit-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "article_conversion_link",
"postId": 7,
"operation": "edit",
"confirmation": "CHANGE_ARTICLE_CONVERSION_LINK",
"changes": {
"title": "Read the next article",
"description": "",
"linkType": "WEB_LINK",
"destinationUrl": "https://example.com/articles/next",
"enabled": true
}
}
}
Original article custom address
The new slug options do not extend alias or delegate policy. Existing create/update, image-description, category/label and dedicated conversion-link contracts retain their own behavior and revisions. No new method, transport or task type is added.
Create with an explicit or automatic address
Keep the ordinary create fields and explicit isPublished choice. Use the post list's selectionRevision as top-level expectedRevision, then optionally add action.articleSlug:
| articleSlug input | Source request and meaning |
|---|---|
| {kind:custom,value:...} | Sanitize the supplied value and send it as postMeta.slug in the same creation POST. |
| {kind:automatic} | Explicitly send postMeta.slug:null, matching the original blank creation field. Observe the returned address; do not derive it from the title. |
| Omitted | Preserve the earlier creation request. Add no metadata solely for slug. If articleImageDescription is supplied, its existing slug:null request remains unchanged. Omission does not opt into the new slug receipt/verification contract. |
articleSlug can compose with articleImageDescription and articleSelection in the same POST. Category and GENERAL selections still need their own revisions. This does not upload images, add a follow-up PUT or allow arbitrary postMeta/SEO fields.
Edit or keep an existing address
Read the ordinary post detail and copy its revision. Use action.kind:set_article_slug with the observed numeric postId, confirmation:CHANGE_ARTICLE_SLUG and slug:{kind:custom,value:...} or slug:{kind:keep}. The dedicated conversion-link revision is not a substitute. keep sends no write and verifies the saved address and full preserved post state. Omission of this action leaves ordinary edits under their existing contracts.
Blank editing is not a proven reset-to-automatic or clear operation. Neither automatic, empty/null clearing nor a reset mode is accepted for set_article_slug. The source edit form removes the first -postId fragment before sending. The bridge supports one unambiguous trailing fragment and rejects an interior/repeated fragment or a bare ID suffix that would be ambiguously removed. For example, editing post7 with My-article-7 submits My-article. A new valid custom value may replace an unusual old address without parsing that old value into a new address.
Sanitization and returned-address bounds
Custom value accepts 1–50 UTF-16 input units before sanitization and must retain at least one allowed character afterward. The original blur transformation removes unsupported characters, trims outer whitespace and replaces each remaining whitespace run with one hyphen. Allowed characters are ASCII letters/digits, hyphens, whitespace, the source Hangul ranges, Hiragana U+3040–U+309F, Katakana U+30A0–U+30FF and CJK U+4E00–U+9FFF. It does not lowercase, transliterate or collapse existing hyphens. For example, My article! becomes My-article. Invalid custom text never silently becomes automatic.
Returned address segments have a separate bridge safety bound of 512 UTF-16 units and must be nonempty and unchanged by sanitization. This is not a 512-unit input allowance or proof of a server generation algorithm. Custom verification accepts only the exact submitted segment or an unambiguous saved submitted-postId that maps back through the source edit transformation. Automatic creation requires a valid nonempty server receipt and an identical fresh post read; it never guesses a slug from a title. Unsafe, ambiguous, missing or unrelated values remain unverified.
Save, preservation and results
Creation uses the existing consumer-scoped POST /seller/api/v1/posts; editing uses PUT /seller/api/v1/posts/{postId}. A slug edit sends only postMeta.slug plus any existing thumbnailAltText and coverAltText individually unchanged. It does not submit other known SEO or unknown metadata fields, and fresh readback must preserve all non-slug metadata exactly, along with body, title, image URLs, category/labels, access references and other article fields. Standard postState counter/reaction/updatedAt exclusions remain. A request already matching the exact saved slug or supported ID form is a no-op; keep/no-op preserves the full state and sends no PUT.
Fresh dryRun:true returns PLAN_READY and articleSlugPlan, including mode as kind, original input, sanitizedInput, submittedSlug, priorSlug where applicable and noWrite. It creates no task or business write. Fresh success remains CONTENT_POST_SAVED with post, revision and taskType:content-post. Explicit slug operations additionally return articleSlug with mode, inputValue, sanitizedInput, submittedSlug, slugFieldSent, priorSlug, savedSlug and articlePath. Absent input/prior values are represented as null in that result. writesPerformed is false for keep/no-op.
articlePath is only the encoded source-relative /channels/{channelCode}/B00001/posts/{savedSlug} when a safe saved segment is available, otherwise null. Accordingly publicUrl is null and publicOriginVerified, generationPolicyVerified, uniquenessVerified and visitorVerified remain false. Do not turn that relative path into a guessed public link. The validated original console detail link remains the primary navigation destination.
verification.slugReadback distinguishes the bounded saved-value check from slugGenerationPolicy:false, slugUniqueness:false, visitor:false, console:false and restoration:false. Creation still has preservation:false because there was no earlier post. Combining image descriptions retains their separate imageDescriptions and visitorAccessibility indicators. A matched source-compatible address is not evidence of domain ownership, redirects, uniqueness policy or visitor success.
Uncertainty and restoration
The durable content-post journal persists sent before dispatch. For creation, the returned post identity and a valid slug receipt are copied into a persisted journal before becoming recoverable. A failed identity write cannot advertise only an in-memory post ID. A malformed/missing slug receipt can leave a valid durable post ID available for inspection, but it cannot establish a verified address even if a later read contains one. CONTENT_CREATE_ID_UNKNOWN never adopts similar content; retain the original task and input.
Sent identical retries and task_resume read only and never repeat POST/PUT. An untouched prepared task follows the ordinary continuation rules with its original input and current checks. Changed credentials/context and reusing the same requestId with different input are rejected. A manually supplied fresh requestId is a separate operation: ordinary post journals do not globally block new requests after an unresolved ordinary write. Reconcile the original task first instead of recreating or resaving to bypass uncertainty. Fresh slug actions also use the existing per-article conversion guard; this does not serialize all legacy journals or external editors.
No source slug-uniqueness lookup or slug-specific duplicate response contract is established. Generic transport codes remain diagnostics; duplicate-like rejection, validation failure or server failure cannot establish uniqueness or trigger a renamed fallback. ARTICLE_SLUG_UNVERIFIED rejects unsupported/ambiguous slug state, ARTICLE_METADATA_UNVERIFIED rejects malformed metadata, and CONTENT_OUTCOME_UNVERIFIED retains uncertainty after mismatched receipt/readback or preservation. There is no atomic revision/ETag or automatic rollback.
After reconciliation, a fresh authorized reverse change may restore an unambiguous prior value. Unusual or overlong original values may require the original console and cannot be universally restored through the 50-unit custom input.
Illustrative previews only. Replace channel, observed IDs and revisions from the matching read; isPublished:false explicitly chooses unpublished creation. Create a custom address with one shared image description:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-slug-create-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "create",
"fields": { "title": "My article", "content": "Article body text." },
"isPublished": false,
"articleImageDescription": "An illustration for the article",
"articleSlug": { "kind": "custom", "value": "My article!" }
}
}
Choose automatic explicitly without deriving an address:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-slug-auto-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "create",
"fields": { "title": "Another article", "content": "Article body text." },
"isPublished": false,
"articleSlug": { "kind": "automatic" }
}
}
Preview a selected article's new custom address using its detail revision:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-slug-edit-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "set_article_slug",
"postId": 7,
"confirmation": "CHANGE_ARTICLE_SLUG",
"slug": { "kind": "custom", "value": "My new article" }
}
}
Explicitly keep the current address; this is not a reset:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-slug-keep-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "set_article_slug",
"postId": 7,
"confirmation": "CHANGE_ARTICLE_SLUG",
"slug": { "kind": "keep" }
}
}
Original article selection candidate
Current source connection: The shared port now forwards bulk deletion through the existing guarded content transport.
Historical candidate boundary (next paragraph only; the heading and anchor remain stable):
Shared deleteContentPosts forwarding and combined integration remain pending.
Prepare article_selection, then send the same channelCode, pAppCode:B00001 and ordered postIds in action.kind:article_selection, its revision as expectedRevision, a stable requestId and optional dryRun (default false). All objects are strict. All 1–100 unique positive safe-integer targets must exist. Missing targets produce ARTICLE_SELECTION_NOT_FOUND; stale selection/context produces CONTENT_CONFLICT. Reusing a request ID with changed normalized input produces REQUEST_ID_REUSED. Only the original B00001 OWNER is supported.
| action.operation | Required confirmation | Source request and skips |
|---|---|---|
| publish | PUBLISH_SELECTED_ARTICLES | One POST /seller/api/v1/posts/{id}/publish with an empty body per changed target. Already-published posts are skipped. |
| unpublish | UNPUBLISH_SELECTED_ARTICLES | One POST /seller/api/v1/posts/{id}/unpublish with an empty body per changed target. Already-unpublished posts are skipped. |
| delete | DELETE_SELECTED_ARTICLES | One POST /seller/api/v1/posts/bulk-delete with a comma-joined ids string for the complete ordered selection. No single-delete loop or missing-target skip is substituted. |
The host supplies the installed consumer, origin, credentials and authorization. A missing shared deletion port returns ARTICLE_SELECTION_TRANSPORT_REQUIRED, including for a new delete dry run. Owner adapter support alone was insufficient; the shared source connection described above now supplies that forwarding.
A fresh dryRun:true returns PLAN_READY with selected summaries and planned:skip/publish/unpublish/delete, writesPerformed:false, atomic:false and removalRecoverable:false. It creates no journal or write. Before a new mutation, the complete semantic snapshots are read again and must agree. This action contains no article body and does not change existing creation, category/general-label or single-post inputs.
Per-target publication and deletion outcomes
Publication is sequential here, whereas the original console saga invokes separate requests in parallel. Before each changed target, the workflow rechecks its original semantic state and durably records an attempt. It stops on target drift, the first transport failure or unverified readback; later targets remain unexecuted. Observing the desired state after a failed transport does not silently continue the remainder. Already-matching skipped rows also need readback; a failed read is not success.
Publication requires the requested isPublished state and preserved unrelated semantic fields. publishedAt may change. Interaction counters and updatedAt are outside semantic comparison, while unknown semantic fields remain protected.
Deletion records every target attempted before one bulk POST, then reads each exact target separately. Successful acknowledgement gives no per-target receipt or transaction guarantee; no exact HTTP success status is invented. Only verified dedicated post absence establishes completed deletion. Installation/authentication preflight errors, malformed responses and foreign records are not absence. Shared forwarding and combined preflight-versus-absence validation were pending at the historical candidate boundary; the current source connection above supersedes that dependency status.
Deletion has no source undo or automatic rollback. Recreating an article would not restore its original ID, comments, links or history. Publication reversal requires fresh preparation and does not restore timestamps or prove visitor effects.
| Target state | Meaning |
|---|---|
| unexecuted | No attempt recorded for this target; recovery may observe it but never sends it. |
| unchanged | Already in the desired publication state; unchanged semantic state must be observed to count toward completion. |
| completed | Recorded readback matched publication/preservation or dedicated deletion absence. |
| failed | Known failure, such as drift before sending or rejected/not_sent transport with unchanged readback. |
| uncertain | Requested effect/preservation cannot be confirmed, or a required read failed. Reconcile attempted uncertain targets before new writes. |
ARTICLE_SELECTION_DONE requires all rows completed/unchanged with observedAt. Otherwise ARTICLE_SELECTION_PARTIAL returns status:action_required with targets, counts, diagnostics and nextStep. Target rows include requestAttempted, before/after summaries, afterObserved, observationHistorical:true and observedAt. Results have currentSnapshot:false, atomic:false and no causality/console/restoration proof.
writeRequestsAttempted counts durable attempt markers, not proven dispatches (one for attempted bulk deletion). writesPerformed is false without attempts, true for a fully observed attempted operation, and "unknown" for an incomplete attempted operation. Partial effects are possible; this is not a transaction.
Selection recovery and target guards
Use existing taskType:content-post, the original taskId and full original input. Saved phases are prepared, sent and verified; task status exposes verified as done. Status is historical. Resume and exact apply retries never send a mutation request, even for prepared work or an unexecuted remainder. Unresolved recovery reports readOnlyRecovery:true, writesPerformed:false and writeRequestsAttemptedThisCall:0. Existing-task dry runs and completed replays are historical.
Recovery can issue GET requests to reread nonterminal rows; completed and known-failed rows retain their recorded observations and timestamps. Unexecuted rows remain unexecuted even when their current value matches, so the task can remain partial after all attempted rows reconcile. Read a fresh selection for current state, then explicitly confirm a new intended operation for known-failed, unexecuted or completed targets. Reconcile attempted uncertain targets first.
Per-target locks coordinate overlapping selections, ordinary post changes and conversions. ARTICLE_SELECTION_PENDING blocks fresh writes on an uncertain attempted target, including a fresh requestId. Missing guard journals fail closed. Existing unresolved conversion guards also block selection writes. Old single-post/conversion journals remain unchanged; this is not a global guard for every older workflow or external editor. Persistence failure cannot promote an in-memory outcome beyond durable progress.
The parent article list does not preselect IDs. Reselect page/search/filters and inspect every target; a link or saved outcome is not current confirmation.
Complete selection dry-run examples
Replace the observed IDs and all-zero placeholder revision with the exact article_selection getter revision. The examples are unchanged; source integration does not imply that the running endpoint has been updated.
Publish:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-selection-publish-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "article_selection",
"operation": "publish",
"postIds": [
7,
8
],
"confirmation": "PUBLISH_SELECTED_ARTICLES"
}
}
Unpublish:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-selection-unpublish-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "article_selection",
"operation": "unpublish",
"postIds": [
7,
8
],
"confirmation": "UNPUBLISH_SELECTED_ARTICLES"
}
}
Delete:
{
"channelCode": "selected-channel",
"pAppCode": "B00001",
"requestId": "article-selection-delete-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "article_selection",
"operation": "delete",
"postIds": [
7,
8
],
"confirmation": "DELETE_SELECTED_ARTICLES"
}
}
Change an original article assignee
The existing tools and guarded transport are connected in source.
Use the dedicated assignee read for one exact B00001 post as OWNER. Preserve channelCode, pAppCode and postId; choose a profileId from that article's fresh complete candidates. Both IDs are positive safe integers. Supply action.kind:article_assignee, confirmation:CHANGE_ARTICLE_ASSIGNEE, its expectedRevision and a stable requestId. The existing request-ID format applies; revision is 64 lowercase hexadecimal characters and dryRun defaults to false.
There is no caller-supplied role, identity, candidate object, assignee array, clear/null value or person-creation action. No alias/delegate/creator-operator access is added. New input rereads current assignment, candidates and post, requires the dedicated revision, then requires a second equal snapshot before any effect. A fresh dry run returns PLAN_READY, requestedAssignee, noop and writesPerformed:false, with no job or mutation.
The source request is POST /seller/api/v1/posts/{postId}/assignees/set, despite the original repository's api.put/PUT_ASSIGNEE names. Its body contains exactly one complete freshly discovered candidate in assignees; unknown candidate JSON fields are retained. It has no query or separate notification request. The common port rechecks selected-channel authorization, installed consumer and credentials around requests and rejects redirects. Endpoint failure never means unassigned.
Selecting the current profile is a no-op only when role/identity/profileId agree with the candidate. It sends no POST, but a real apply still saves the task and verifies the observed assignment. Multiple current assignees prevent mutation; reconcile them in the original console rather than silently replacing a list. Missing or changed candidates require a fresh read and explicit selection.
Assignment results and preservation
ARTICLE_ASSIGNEE_SAVED requires the dedicated endpoint to report exactly the selected role/identity/profileId and all other semantic post fields to remain unchanged. The optional Post.assignees projection must agree when present. Existing interaction counters and updatedAt are excluded as in ordinary post workflows. Candidate profile display metadata may change independently; matching identity does not promise a fixed nickname or image.
The result includes beforeAssignees, requestedAssignee, observed assignees, requestAttempted, writesPerformed, observedAt, verification and restoration limits. A matching no-op has no attempted mutation. Readback/preservation confirmation is sequential and non-atomic; causality, console equality, notification effects and restoration remain false/unverified.
| Result or error | Meaning and next action |
|---|---|
| CONTENT_CONFLICT | Post, assignment, candidates or context changed; read the dedicated view again before planning new work. |
| ARTICLE_ASSIGNEE_NOT_ELIGIBLE | The selected profileId is absent from the current candidates. |
| ARTICLE_ASSIGNEE_MULTIPLE_CURRENT | More than one current assignee; no mutation is sent. |
| ARTICLE_ASSIGNEE_IDENTITY_CHANGED | Current and candidate records disagree for the same profile. |
| ARTICLE_ASSIGNEE_OUTCOME_UNVERIFIED | An attempted assignment cannot be verified; preserve the original task and observe without replay. |
| ARTICLE_ASSIGNEE_NOT_SENT | The saved non-no-op task has no durable attempted boundary; exact retry/resume still does not send it. |
| ARTICLE_ASSIGNEE_REJECTED | Transport was known not-sent/rejected and readback is fully unchanged; a new deliberate request needs fresh candidates/revision. |
| ARTICLE_ASSIGNEE_PENDING | An unresolved attempted assignment or orphan marker blocks a fresh mutation of this article. |
Unknown results expose requestedAssignee, requestAttempted, transportCode and diagnostic while snapshotHistorical:true marks the original displayed snapshot. A matching visible value without preserved post fields is not completion. Context or authorization failure prevents verified results and cached snapshot disclosure.
Assignment recovery and target protection
The canonical task remains content-post. The task and per-article marker are persisted before the attempted/sent boundary, which precedes POST. The marker is scoped to the connection, channel, exact app installation and post in the same task store. Unknown attempted outcomes block fresh assignment, ordinary post, selected-post and conversion mutations. Existing selected-post/conversion guards also prevent a new assignment. An orphan marker fails closed; a new requestId, fresh revision or ordinary read cannot clear attempted uncertainty.
Identical apply retries and task_resume only observe an existing assignment task, including prepared work that never reached the attempted boundary. They never send or replay an assignment. A known unattempted non-no-op task remains ARTICLE_ASSIGNEE_NOT_SENT after observation; its marker does not represent an attempted-effect block. Any later intended assignment uses a fresh read, new requestId and explicit confirmation. Stored verified/rejected outcomes are historical. A dry run against an existing task returns a historical plan without a new effect.
Recovering old selected-post/conversion journals remains observational; the new guard does not rewrite them. Do not infer global coordination of every ordinary-post journal, other storage/grant contexts, external API calls or manual console edits. No automatic rollback is performed. Task status is saved evidence rather than current readback.
Restoration and navigation limits
The fresh read and verified save use the exact original post detail destination. Use the returned validated link; it does not preselect a person or prove notification delivery. Historical task status and terminal replay receive no current result link.
To select a previous assignee again, first resolve the original task, read fresh eligible candidates and the new revision, then explicitly select the previous profileId under a new requestId. A previously eligible person may no longer be available. Returning to a formerly unassigned state, assigning multiple people, clearing assignment and reversing notification effects are unsupported. No automatic notification suppression or reversal is inferred from the absence of a separate notification-send request.
Source integration, exact-revision fixture evidence, translation backlog and D-PLAN-1 remain separate.
Complete assignee dry-run examples
Replace IDs with the exact post and discovered candidate. The all-zero revision is a placeholder for the dedicated read; these inputs are not actual calls or permission to send notifications.
Preview selecting a discovered candidate.
{
"channelCode": "channel98",
"pAppCode": "B00001",
"requestId": "article-assignee-example",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "article_assignee",
"postId": 7,
"profileId": 11,
"confirmation": "CHANGE_ARTICLE_ASSIGNEE"
}
}
Preview restoring a previous person only after a new read confirms profileId:10 is still eligible. Use that new revision, not the one from the original assignment.
{
"channelCode": "channel98",
"pAppCode": "B00001",
"requestId": "article-assignee-restore-example",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"dryRun": true,
"action": {
"kind": "article_assignee",
"postId": 7,
"profileId": 10,
"confirmation": "CHANGE_ARTICLE_ASSIGNEE"
}
}
Article ordinary-edit retention
Ordinary article-family updates retain the source-compatible saved slug and independent nonempty image descriptions from the fresh post read. Optional blank/absent descriptions are omitted, as in the original editor; malformed descriptions and missing/ambiguous slugs still block dispatch. Omission does not request clearing and may produce the saved-title default. No caller canonical URL, metadata timestamp or general SEO input is exposed.
New ordinary-edit journals use the versioned source-editor-v2 policy. articleMetadataObservation reports exact allowed system changes: an omitted description may remain absent/blank or receive the saved title; an existing metaTitle/ogTitle equal to the previous post title may follow the exact requested title; a changed metadata timestamp must be valid and non-regressing. Canonical URL, slug, custom descriptions/SEO titles and all other metadata remain protected. Arbitrary generated values, malformed/missing changed timestamps and unexpected fields do not pass. Stored timestamps remain in revisions; no global field exclusion is introduced. A successful business edit is not a claim that timestamps or omitted defaults can be restored.
Earlier sent jobs, including those with the original retained-slug marker but no new policy marker, keep their old strict verification and observation-only recovery.
Source conversion projection and hosted persistence
The original seller post API embeds a conversion object without its numeric id. The reader verifies its known fields against the dedicated link and exact post; a conflicting object never means absent. New source-conversion-v1 write journals permit that verified projection to follow initialization/editing while preserving all other post values and unknown fields. Existing journals retain their earlier strict comparison and observation-only retry. The workflow writes its pending guard through the same store instance holding the hosted lock. See the backend contract correction.
Timeline asynchronous video creation
Exact A00001/A9xx01 OWNER can use action.kind:timeline_video_create on the
existing method. First upload actual video bytes with the existing
content_file_upload timeline_video purpose. Then read
content_posts_get timeline_video_creation for that acknowledged upload task.
Apply its revision with a stable requestId, confirmation CREATE_TIMELINE_VIDEO,
uploadTaskId, content (2–20,000 UTF-16 units), isPublished, existing numeric
labelIds and existing string contentCatalogIds. Empty arrays are allowed unless
the installed app requires a label. The default empty catalog selection means no
initial catalog link. Public video URLs, supplied author/profile, caller duration,
schedules and publishedAt are not accepted. Generic synchronous create still
rejects VIDEO.
The workflow sends the original STORY/VIDEO body once through the closed common
candidate capability. It stores sent intent before dispatch and persists the
returned candidate ID and UUID before independent observation. Success of that
observation is reported as TIMELINE_VIDEO_CANDIDATE_OBSERVED with
status:action_required, postSaved:false and postIdentity:not_provided.
Even a later POSTED state is not a final post or playback success.
Retry or task_resume with taskType:content-post observes only the exact stored
ID plus UUID and retained body/actor. No upload or create is replayed. A missing
receipt remains TIMELINE_VIDEO_OUTCOME_UNVERIFIED, even if the list contains
similar content. The same acknowledged upload is permanently claimed by its
candidate request and cannot create again under a new request ID. Recovery scans
at most 2,000 candidates; a missing/changed identity or unavailable old page stays
unresolved, rather than assuming absence or recreating content.
Use the normal post list to select any result explicitly, followed by
timeline_video_result for an independent comparison. The backend does not
provide an authoritative candidate-to-post link. Verify the exact original
console and video playback separately before declaring completion. Deleting a
selected verification post uses the existing fresh-revision delete flow; this
workflow offers no invented candidate-delete or storage-cleanup endpoint.