[{"slug":"ZV-2026-1770","server_name":"api.uplika.com","severity":"breaking","title":"api.uplika.com: Type of post on create_comment_to_dm changed unset → string.","summary":"[safe] Tool delete_automation was added. [safe] Tool duplicate_automation was added. [safe] Tool get_help was added. [safe] Tool list_automation_versions was added. [safe] Tool update_automation was added. [safe] Tool validate_automation was added. [safe] Description of bridge_status changed (13% word delta). [risky] Description of create_comment_to_dm changed (26% word delta). [breaking] Type of post on create_comment_to_dm changed unset → string. [safe] Description of delete_post changed (17% word delta). [safe] Description of diagnose_naver_blog changed (8% word delta). [risky] Description of enable_automation changed (36% word delta). [risky] Description of expand_naver_keywords changed (46% word delta). [risky] Description of follow changed (30% word delta). [risky] Description of get_automation changed (34% word delta). [risky] Optional field version was added to get_automation; may shift model behaviour. [risky] Description of get_insights changed (43% word delta). [safe] Description of get_naver_keyword_history changed (17% word delta). [risky] Description of get_post changed (42% word delta). [risky] Description of like changed (37% word delta). [risky] Description of list_automation_runs changed (48% word delta). [risky] Description of list_automations changed (34% word delta). [risky] Optional field accountId was added to list_automations; may shift model behaviour. [risky] Optional field status was added to list_automations; may shift model behaviour. [risky] Optional field templateId was added to list_automations; may shift model behaviour. [safe] Description of list_channel_posts changed (23% word delta). [risky] Description of list_mentions changed (62% word delta). [safe] Description of list_naver_drafts changed (24% word delta). [safe] Description of list_naver_keyword_reports changed (19% word delta). [risky] Description of list_replies changed (39% word delta). [safe] Description of media_from_url changed (24% word delta). [risky] Description of m","changes":[{"kind":"tool_added","tool":"delete_automation","detail":"Tool `delete_automation` was added.","severity":"safe"},{"kind":"tool_added","tool":"duplicate_automation","detail":"Tool `duplicate_automation` was added.","severity":"safe"},{"kind":"tool_added","tool":"get_help","detail":"Tool `get_help` was added.","severity":"safe"},{"kind":"tool_added","tool":"list_automation_versions","detail":"Tool `list_automation_versions` was added.","severity":"safe"},{"kind":"tool_added","tool":"update_automation","detail":"Tool `update_automation` was added.","severity":"safe"},{"kind":"tool_added","tool":"validate_automation","detail":"Tool `validate_automation` was added.","severity":"safe"},{"kind":"description_changed","tool":"bridge_status","after":"Naver Blog only. Posts to Naver Blog are written by the uplika browser extension inside the user's own Chrome, so nothing goes out while that Chrome is closed. Call this before publishing to Naver Blog. If online is false, the response carries wake commands per OS that open Chrome on the user's computer in the profile that has the extension (found by extension id), for the person to run. Once Chrome is open the extension reconnects within about a minute and queued posts go out; call this again or get_post to check. publish also returns the same bridge object when the extension is offline. state is one of online, offline, logged_out (Chrome is on but not logged in to Naver), login_needed (the Naver login saved for that blog in that Chrome is signed out; its posts wait until the person logs in again from the dashboard). userMessage is a sentence in the person's language to relay as it is. queued is how many posts wait for the extension; delete_post cancels them and update_post rewrites them before they go out. extensionVersion and kinds say what that extension can do.","before":"Naver Blog only. Posts to Naver Blog are written by the uplika browser extension inside the user's own Chrome, so nothing goes out while that Chrome is closed. Call this before publishing to Naver Blog. If online is false, the response carries wake commands per OS that open Chrome on the user's computer in the profile that has the extension (found by extension id). If you have a shell on that computer, run the one for its OS, then call this again or get_post; the extension reconnects within about a minute and queued posts go out. publish also returns the same bridge object when the extension is offline. state is one of online, offline, logged_out (Chrome is on but not logged in to Naver). userMessage is a sentence in the person's language to relay as it is. queued is how many posts wait for the extension; delete_post cancels them and update_post rewrites them before they go out. extensionVersion and kinds say what that extension can do.","detail":"Description of `bridge_status` changed (13% word delta).","severity":"safe","descriptionDelta":0.12612612612612617},{"kind":"description_changed","tool":"create_comment_to_dm","after":"The most common automation: when someone comments on a post, DM them. **Creates a draft; nothing goes out until enable_automation.** How Meta works: a DM cannot be started by the account. The only automatic door is a private reply to a comment, one per comment, within 7 days of the comment, and once the person answers the 24-hour window opens for the rest. Instagram can check whether the person follows the account (requireFollow); Facebook cannot, so requireFollow is rejected there. Threads has no DMs at all; use create_automation with comment_public_reply. A file to deliver: if it already has a public https link that returns the file itself (jpeg, png, gif, webp, mp4, mov or PDF), pass it as deliver.fileUrl and it goes to the person as-is; the link is opened once on save and a web page (a Google Drive or Dropbox share page), a private address or a dead link is rejected. If the file has no public link, upload it to Uplika first (media_upload_link without a shell, media_presign then media_complete with one) and pass deliver.mediaId (photos, videos, PDF or HWP/HWPX documents; on Instagram a document other than PDF goes as a download link, because Instagram DMs attach PDF only). Not both. post can be our post id, the post's own id on the platform, a link to the post, \"any\" for every post, or \"next\" for the next post you publish (or pass automation on publish to do both in one call). Only one enabled automation per account can wait for \"next\" (409 next_post_taken). Order when everything is on: opening DM (message + button) -> askEmail -> requireFollow -> deliver (text, up to three link buttons, file; clicks are tracked) -> followUp if no link was clicked. openingDm:false sends deliver as the private reply itself; then requireFollow, askEmail, followUp and files are rejected because the window never opens.","before":"The most common automation: when someone comments on a post, DM them. **Creates a draft; nothing goes out until enable_automation.** How Meta works: a DM cannot be started by the account. The only automatic door is a private reply to a comment, one per comment, within 7 days of the comment, and once the person answers the 24-hour window opens for the rest. Instagram can check whether the person follows the account (requireFollow); Facebook cannot, so requireFollow is rejected there. Threads has no DMs at all; use create_automation with comment_public_reply. Files go through media_presign first and are passed as deliver.mediaId. post can be our post id, the post's own id on the platform, a link to the post, \"any\" for every post, or \"next\" for the next post you publish (or pass automation on publish to do both in one call). Only one enabled automation per account can wait for \"next\" (409 next_post_taken). Order when everything is on: opening DM (message + button) -> askEmail -> requireFollow -> deliver (text, up to three link buttons, file; clicks are tracked) -> followUp if no link was clicked. openingDm:false sends deliver as the private reply itself; then requireFollow, askEmail, followUp and files are rejected because the window never opens.","detail":"Description of `create_comment_to_dm` changed (26% word delta).","severity":"risky","descriptionDelta":0.26347305389221554},{"kind":"input_type_changed","path":"inputSchema.properties.post","tool":"create_comment_to_dm","after":"string","before":"unset","detail":"Type of `post` on `create_comment_to_dm` changed unset → string.","severity":"breaking"},{"kind":"description_changed","tool":"delete_post","after":"Delete a post from the channel for good. This is not reversible, so confirm with the person first. Daily delete limits differ per channel: Threads 100 a day, Instagram only on accounts connected via Facebook, with no documented daily cap, YouTube 20 a day, Facebook 50 a day, Bluesky 35000 a day, Telegram only within 48 hours of publishing, with no documented daily cap, Naver Blog through the browser extension, with no documented daily cap, TikTok has no delete API; posts can only be removed in the app. On a scheduled or draft post nothing is on any channel yet, so this simply cancels it and removes our record. A Naver draft (target externalId starting with draft:) is only in Naver's draft box: this cancels our record and, with extension 0.7.2 or later, removes that draft too. On Threads and YouTube this also works on posts written in the channel's own app, given the link. Instagram only lets us delete on accounts connected via Facebook: an account connected with Instagram login cannot be deleted through us at all, so tell the person to delete it in the Instagram app. Facebook only lets us delete Page posts this app published, so a post made in the Facebook app cannot be deleted through us. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Delete a post from the channel for good. This is not reversible, so confirm with the person first. Daily delete limits differ per channel: Threads 100 a day, Instagram only on accounts connected via Facebook, with no documented daily cap, YouTube 20 a day, Facebook 50 a day, Bluesky 35000 a day, Telegram only within 48 hours of publishing, with no documented daily cap, Naver Blog through the browser extension, with no documented daily cap, TikTok has no delete API; posts can only be removed in the app. On a scheduled or draft post nothing is on any channel yet, so this simply cancels it and removes our record. A Naver draft (target externalId starting with draft:) is only in Naver's draft box: this cancels our record and, with extension 0.7.2 or later, removes that draft too. On Threads and YouTube this also works on posts written in the channel's own app, given the link. Instagram only lets us delete on accounts connected via Facebook: an account connected with Instagram login cannot be deleted through us at all, so tell the person to delete it in the Instagram app. Facebook only lets us delete Page posts this app published, so a post made in the Facebook app cannot be deleted through us. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `delete_post` changed (17% word delta).","severity":"safe","descriptionDelta":0.16891891891891897},{"kind":"description_changed","tool":"diagnose_naver_blog","after":"Naver Blog only. Reads a blog's public RSS feed (its latest posts, at most 50) and says whether the titles are written for search: the share of titles carrying a search intent word (price, how to, review), how many start with a date or episode label, posts per month, the categories, and the words the blog repeats in titles (seedCandidates: candidates to research, not proven keywords). summary.oldest and summary.newest say which dates it read, so a quiet blog's 50 posts are not everything; summary.capped is true at 50. flags and thresholds carry the judgement (lowIntent when the intent share is under thresholds.lowIntentPct). Works for any public blog, not only connected ones, and needs no Naver keys. Cached 24 hours; a cache miss spends one of 20 diagnoses per person per day (quota in the response). Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors. Tell them once and do not call it again until they say it is on.","before":"Naver Blog only. Reads a blog's public RSS feed (its latest posts, at most 50) and says whether the titles are written for search: the share of titles carrying a search intent word (price, how to, review), how many start with a date or episode label, posts per month, the categories, and the words the blog repeats in titles (seedCandidates: candidates to research, not proven keywords). summary.oldest and summary.newest say which dates it read, so a quiet blog's 50 posts are not everything; summary.capped is true at 50. flags and thresholds carry the judgement (lowIntent when the intent share is under thresholds.lowIntentPct). Works for any public blog, not only connected ones, and needs no Naver keys. Cached 24 hours; a cache miss spends one of 20 diagnoses per person per day (quota in the response). Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors; tell them to open that link.","detail":"Description of `diagnose_naver_blog` changed (8% word delta).","severity":"safe","descriptionDelta":0.07758620689655171},{"kind":"description_changed","tool":"enable_automation","after":"Turn an automation live. **This is the moment messages start going to real people.** Confirm with the person first. Only one automation per account can wait for the next post: enabling a second one is refused with next_post_taken until the first binds to a post. Refuses with reconsent_required if the account does not hold the DM permissions (the person reconnects it), with feature_in_review if the flow uses a feature whose permission is still in Meta app review (a mention trigger, liking a comment on Instagram) and the account does not already hold it, and warns if the account is not subscribed to webhooks.","before":"Turn an automation live. **This is the moment messages start going to real people.** Confirm with the person first. Only one automation per account can wait for the next post: enabling a second one is refused with next_post_taken until the first binds to a post. Refuses with reconsent_required if the account was connected before DM permissions, and warns if the account is not subscribed to webhooks.","detail":"Description of `enable_automation` changed (36% word delta).","severity":"risky","descriptionDelta":0.3623188405797102},{"kind":"description_changed","tool":"expand_naver_keywords","after":"Naver Blog only. Expands seed keywords one level through Naver autocomplete and returns every word found with the seed it came from (found[].from is seed or L1:<seed>). These are candidates to measure with research_naver_keywords, not proven keywords. The person's uplika Chrome extension looks them up in the background when it is on (no window opens); otherwise our server does, and via says which path answered each seed. Up to 10 seeds. Cached seven days. There is no daily cap: the extension path has no wait, and when our server answers, each person gets one expansion every 60 seconds (naver_autocomplete_busy says how long to wait). When the answer is naver_autocomplete_unavailable, neither path could run: pass your own keyword list to research_naver_keywords instead. naver_autocomplete_paused and naver_autocomplete_busy carry retryAfterSeconds. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors. Tell them once and do not call it again until they say it is on.","before":"Naver Blog only. Expands seed keywords one level through Naver autocomplete on the server and returns every word found with the seed it came from (found[].from is seed or L1:<seed>). These are candidates to measure with research_naver_keywords, not proven keywords. Up to 10 seeds. Cached seven days; a call with at least one uncached seed spends one of 20 expansions per person per day. Server-side autocomplete is off by default: when the server answers naver_autocomplete_unavailable, pass your own keyword list to research_naver_keywords instead. naver_autocomplete_paused and naver_autocomplete_busy carry retryAfterSeconds. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors; tell them to open that link.","detail":"Description of `expand_naver_keywords` changed (46% word delta).","severity":"risky","descriptionDelta":0.4590163934426229},{"kind":"description_changed","tool":"follow","after":"Follow an account on the channel. Naver Blog only today: adds the blog as a neighbor. mutual: true sends a mutual-neighbor request that the other blog has to accept, so the result is pending until they do; without it the blog is added as a plain neighbor right away. Already a neighbor comes back as already. There is no unfollow. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Follow an account on the channel. Naver Blog only today: adds the blog as a neighbor. mutual: true sends a mutual-neighbor request that the other blog has to accept, so the result is pending until they do; without it the blog is added as a plain neighbor right away. Already a neighbor comes back as already. There is no unfollow. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `follow` changed (30% word delta).","severity":"risky","descriptionDelta":0.29670329670329665},{"kind":"description_changed","tool":"get_automation","after":"One automation as a document: triggers, nodes, start. Also returns version, which put_automation and update_automation need, and templateParams when the flow still has its template shape. Pass version to read an older saved version's document instead (list_automation_versions).","before":"One automation as a document: triggers, nodes, start. Also returns version, which put_automation needs, and templateParams when the flow still has its template shape.","detail":"Description of `get_automation` changed (34% word delta).","severity":"risky","descriptionDelta":0.34285714285714286},{"kind":"input_property_added","path":"inputSchema.properties.version","tool":"get_automation","after":{"type":"integer","description":"A saved version number from list_automation_versions. Leave out for the current one."},"detail":"Optional field `version` was added to `get_automation`; may shift model behaviour.","severity":"risky"},{"kind":"description_changed","tool":"get_insights","after":"Views, likes, replies, reposts, quotes and shares for one publish. Views and shares can be null when the platform does not report them yet — null is not zero. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Views, likes, replies, reposts, quotes and shares for one publish. Views and shares can be null when the platform does not report them yet — null is not zero. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `get_insights` changed (43% word delta).","severity":"risky","descriptionDelta":0.4285714285714286},{"kind":"description_changed","tool":"get_naver_keyword_history","after":"The measurement history of one keyword: one point per day it was actually measured, newest first, with search volume, document count and posts per month. Shows whether a keyword is rising or cooling. An empty list means nobody has measured it here yet. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors. Tell them once and do not call it again until they say it is on.","before":"The measurement history of one keyword: one point per day it was actually measured, newest first, with search volume, document count and posts per month. Shows whether a keyword is rising or cooling. An empty list means nobody has measured it here yet. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors; tell them to open that link.","detail":"Description of `get_naver_keyword_history` changed (17% word delta).","severity":"safe","descriptionDelta":0.171875},{"kind":"description_changed","tool":"get_post","after":"One publish: per-target status and the reason any target failed. For a post link you probably want open_post instead. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"One publish: per-target status and the reason any target failed. For a post link you probably want open_post instead. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `get_post` changed (42% word delta).","severity":"risky","descriptionDelta":0.4246575342465754},{"kind":"description_changed","tool":"like","after":"Like a post — or a comment: pass replyTo (a reply id from list_replies) to like that comment instead of the post. Idempotent: if it is already liked the call succeeds with already: true and nothing is toggled. There is no unlike. Works on Naver Blog and on Instagram accounts connected through Facebook that hold the like permission; any other Instagram account and every other channel answer not_supported. A Facebook-connected Instagram account without that permission answers feature_in_review while the permission is in Meta app review (list_platforms shows the state), and reconsent_required once it can be granted by reconnecting. On Naver Blog the post can belong to another blog: pass its link and we act as the connected account. Naver ignores liking your own post, and that comes back as naver_not_allowed rather than a fake success. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Like a post — or a comment: pass replyTo (a reply id from list_replies) to like that comment instead of the post. Idempotent: if it is already liked the call succeeds with already: true and nothing is toggled. There is no unlike. Works on Naver Blog and on Instagram accounts connected through Facebook; other channels answer not_supported. On Naver Blog the post can belong to another blog: pass its link and we act as the connected account. Naver ignores liking your own post, and that comes back as naver_not_allowed rather than a fake success. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `like` changed (37% word delta).","severity":"risky","descriptionDelta":0.3656716417910447},{"kind":"description_changed","tool":"list_automation_runs","after":"Runs of one automation with their status and a step log. Status says where a run is or why it stopped: running, waiting, done, superseded, blocked_window (24-hour window closed), blocked_opt_out, blocked_paused (a person is handling that conversation), blocked_burst, blocked_ai_quota (the workspace used its daily automation AI limit; it resets at 00:00 UTC), failed_channel, failed_ai (the AI step could not classify the comment or write the reply; the reason is in the log as classify_failed or ai_failed), expired.","before":"Runs of one automation with their status and a step log. Status names why a run stopped: blocked_window (24-hour window closed), blocked_opt_out, blocked_paused (a person is handling that conversation), blocked_burst, failed_channel, expired, superseded, waiting, done.","detail":"Description of `list_automation_runs` changed (48% word delta).","severity":"risky","descriptionDelta":0.4838709677419355},{"kind":"description_changed","tool":"list_automations","after":"Automations on the connected accounts: name, channel, whether it is live or a draft, triggers, run count, and templateParams when the flow still has its template shape. Filter by accountId, status (draft or live) or templateId. Use get_automation to read one flow's document.","before":"Automations on the connected accounts: name, channel, whether it is live or a draft, triggers, run count. Use get_automation to read one flow's document.","detail":"Description of `list_automations` changed (34% word delta).","severity":"risky","descriptionDelta":0.3421052631578947},{"kind":"input_property_added","path":"inputSchema.properties.accountId","tool":"list_automations","after":{"type":"string","description":"Only automations on this connected account."},"detail":"Optional field `accountId` was added to `list_automations`; may shift model behaviour.","severity":"risky"},{"kind":"input_property_added","path":"inputSchema.properties.status","tool":"list_automations","after":{"enum":["draft","live"],"type":"string","description":"draft = not enabled, live = enabled."},"detail":"Optional field `status` was added to `list_automations`; may shift model behaviour.","severity":"risky"},{"kind":"input_property_added","path":"inputSchema.properties.templateId","tool":"list_automations","after":{"type":"string","description":"Only automations made from this template (list_automation_templates)."},"detail":"Optional field `templateId` was added to `list_automations`; may shift model behaviour.","severity":"risky"},{"kind":"description_changed","tool":"list_channel_posts","after":"What is actually on the channel right now, including posts written in the channel's own app. Use this to find a post when you do not have its link. Each item carries a permalink you can pass straight to open_post, reply or delete_post. An empty list does not always mean the account has no posts: on TikTok this reads public videos only, so it stays empty while the app is awaiting TikTok's Content Posting audit and every post goes out private. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"What is actually on the channel right now, including posts written in the channel's own app. Use this to find a post when you do not have its link. Each item carries a permalink you can pass straight to open_post, reply or delete_post. An empty list does not always mean the account has no posts: on TikTok this reads public videos only, so it stays empty while the app is awaiting TikTok's Content Posting audit and every post goes out private. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `list_channel_posts` changed (23% word delta).","severity":"safe","descriptionDelta":0.2272727272727273},{"kind":"description_changed","tool":"list_mentions","after":"Threads posts that mention the connected account, delivered by webhook. Same shape as list_conversations with kind mention. Reply with send_dm, which posts publicly. Mentions need a permission of their own: when no connected Threads account holds it the list is empty and the response carries notice (code feature_in_review while that permission is in Meta app review, reconsent_required once reconnecting grants it). list_platforms shows the state.","before":"Threads posts that mention the connected account, delivered by webhook. Same shape as list_conversations with kind mention. Reply with send_dm, which posts publicly.","detail":"Description of `list_mentions` changed (62% word delta).","severity":"risky","descriptionDelta":0.6153846153846154},{"kind":"description_changed","tool":"list_naver_drafts","after":"Naver Blog only. Lists the drafts (temp-saved posts) sitting in the blog's draft box: logNo, title and the last-saved time, newest first. A post you published with options.naver_blog.draftOnly is one of them, and so is anything the person saved by hand in the Naver editor. Pass a logNo from here to publish_naver_draft. Needs the extension 0.7.2 or later in the person's Chrome; otherwise you get extension_outdated. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Naver Blog only. Lists the drafts (temp-saved posts) sitting in the blog's draft box: logNo, title and the last-saved time, newest first. A post you published with options.naver_blog.draftOnly is one of them, and so is anything the person saved by hand in the Naver editor. Pass a logNo from here to publish_naver_draft. Needs the extension 0.7.2 or later in the person's Chrome; otherwise you get extension_outdated. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `list_naver_drafts` changed (24% word delta).","severity":"safe","descriptionDelta":0.23529411764705888},{"kind":"description_changed","tool":"list_naver_keyword_reports","after":"Lists the person's saved keyword research (from research_naver_keywords or the dashboard), newest first: when, what they typed, the first set's main and sub keywords, and every set with its prompt. Reports belong to the person, not a workspace. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors. Tell them once and do not call it again until they say it is on.","before":"Lists the person's saved keyword research (from research_naver_keywords or the dashboard), newest first: when, what they typed, the first set's main and sub keywords, and every set with its prompt. Reports belong to the person, not a workspace. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors; tell them to open that link.","detail":"Description of `list_naver_keyword_reports` changed (19% word delta).","severity":"safe","descriptionDelta":0.19298245614035092},{"kind":"description_changed","tool":"list_replies","after":"The whole reply thread under a post, nested replies included. `truncated` tells you we stopped before the end. The count here can differ from the replies metric in get_insights, which is normal. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"The whole reply thread under a post, nested replies included. `truncated` tells you we stopped before the end. The count here can differ from the replies metric in get_insights, which is normal. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `list_replies` changed (39% word delta).","severity":"risky","descriptionDelta":0.3855421686746988},{"kind":"description_changed","tool":"media_from_url","after":"Attach an image or video that is already on the public web. We download it, copy it into our storage and give you a media id you can pass to publish. One step, no upload needed. https only. Google Drive and Dropbox **share** links do not work: they return an HTML preview page, not the file. Use a direct file URL that ends in the file itself. Accepted formats (read from the bytes, not the headers): image/jpeg, image/png, image/gif, image/webp, video/mp4, video/quicktime. Each channel then checks what it takes when you publish. If you can see the image, write altText describing it.","before":"Attach an image or video that is already on the public web. We download it, copy it into our storage and give you a media id you can pass to publish. One step, no upload needed. https only. Google Drive and Dropbox **share** links do not work: they return an HTML preview page, not the file. Use a direct file URL that ends in the file itself. If you can see the image, write altText describing it.","detail":"Description of `media_from_url` changed (24% word delta).","severity":"safe","descriptionDelta":0.23750000000000004},{"kind":"description_changed","tool":"media_presign","after":"Use this only when you can HTTP PUT the file bytes yourself (a shell or code runtime). Web and mobile chat clients cannot, so do not call it there: for a file on the person's device use media_upload_link, for a public https address use media_from_url. Returns a media id and a one-time uploadUrl. PUT the file bytes to uploadUrl with the same contentType, then call media_complete. Images: image/jpeg, image/png, image/webp, image/gif, up to 20MB. Video: video/mp4, video/quicktime, video/webm, up to 8GB, 43200 seconds, 4096px wide. Aspect ratio up to 20:1. Any image pixel width is fine. Documents for DM automations only (deliver.mediaId), not for posts: application/pdf, application/x-hwp, application/hwp+zip (.pdf, .hwp, .hwpx), up to 25MB. If you can see the image, write altText describing it. The response has mediaExpiresAt: this media id disappears after that time if it was never published, and publish will then fail with media_expired.","before":"Step 1 of attaching an image or video. Returns a media id and a one-time uploadUrl. PUT the file bytes to uploadUrl with the same contentType, then call media_complete. Images: image/jpeg, image/png, image/webp, image/gif, up to 20MB. Video: video/mp4, video/quicktime, video/webm, up to 8GB, 43200 seconds, 4096px wide. Aspect ratio up to 20:1. Any image pixel width is fine. If you can see the image, write altText describing it. The response has mediaExpiresAt: this media id disappears after that time if it was never published, and publish will then fail with media_expired.","detail":"Description of `media_presign` changed (39% word delta).","severity":"risky","descriptionDelta":0.3928571428571429},{"kind":"description_changed","tool":"media_upload_link","after":"Ask the person to upload files from their own device. Returns a short-lived link. **Give the link to the person, then wait.** Poll media_upload_status with the token until it returns ready, and only then call publish with the media ids it gives you. Do not publish before the status is ready. Use this when the file is on their computer or phone; use media_from_url when the file already has a public https address. The page also takes PDF and HWP/HWPX documents, for a DM automation's file (deliver.mediaId); a post cannot carry them.","before":"Ask the person to upload files from their own device. Returns a short-lived link. **Give the link to the person, then wait.** Poll media_upload_status with the token until it returns ready, and only then call publish with the media ids it gives you. Do not publish before the status is ready. Use this when the file is on their computer or phone; use media_from_url when the file already has a public https address.","detail":"Description of `media_upload_link` changed (25% word delta).","severity":"safe","descriptionDelta":0.24637681159420288},{"kind":"description_changed","tool":"open_post","after":"Everything about one post in a single call: the text, the whole reply thread, and its metrics. This is the right tool when someone hands you a post link. Replies or metrics can come back null if the platform refused just that part. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Everything about one post in a single call: the text, the whole reply thread, and its metrics. This is the right tool when someone hands you a post link. Replies or metrics can come back null if the platform refused just that part. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `open_post` changed (33% word delta).","severity":"risky","descriptionDelta":0.3295454545454546},{"kind":"description_changed","tool":"publish_naver_draft","after":"Naver Blog only. Publishes a draft from the blog's draft box exactly as it is in Naver: the extension loads that draft in the editor and presses publish, so edits the person made by hand in Naver are kept. Do not send content. Category, tags and openType are taken from the draft unless you pass them. Returns the same shape as publish (202 with a target that resolves to published, or the bridge object when the extension is offline; wait: true holds until it settles). If that draft was made through uplika (a target whose externalId starts with draft:), the same post record flips to published instead of a second one appearing. To publish uplika's own copy of the text rather than what is in Naver, use update_post on that post instead. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Naver Blog only. Publishes a draft from the blog's draft box exactly as it is in Naver: the extension loads that draft in the editor and presses publish, so edits the person made by hand in Naver are kept. Do not send content. Category, tags and openType are taken from the draft unless you pass them. Returns the same shape as publish (202 with a target that resolves to published, or the bridge object when the extension is offline; wait: true holds until it settles). If that draft was made through uplika (a target whose externalId starts with draft:), the same post record flips to published instead of a second one appearing. To publish uplika's own copy of the text rather than what is in Naver, use update_post on that post instead. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `publish_naver_draft` changed (17% word delta).","severity":"safe","descriptionDelta":0.16935483870967738},{"kind":"description_changed","tool":"put_automation","after":"Edit an automation by replacing its whole document: for flows no template covers, or that were already edited on the canvas. If get_automation shows templateParams, change it with update_automation instead (only the params you pass change; an Instagram follow check is requireFollow, notFollowingMessage and recheckTitle). Replacing the document of a flow that still has its template form is refused with automation_is_template, because the person can no longer open it in the form afterwards; pass detachTemplate: true only when the change cannot be expressed as template params. Read it first with get_automation and pass the version you got; a stale version is refused with version_conflict so a concurrent edit is not overwritten. Node types: send (mode window | private_reply | public_reply), condition, action, delay, random, goto, ai. Waiting is a send node with buttons and next: null; the tapped button's next continues. A loop must pass through such a wait. Validation problems come back with paths. Changing a live flow changes what goes out to people.","before":"Edit an automation: change its triggers, messages or steps by replacing its whole document (there is no partial update). Read it first with get_automation and pass the version you got; a stale version is refused with version_conflict so a concurrent edit is not overwritten. Node types: send (mode window | private_reply | public_reply), condition, action, delay, random, goto, ai. Waiting is a send node with buttons and next: null; the tapped button's next continues. A loop must pass through such a wait. Validation problems come back with paths. Changing a live flow changes what goes out to people.","detail":"Description of `put_automation` changed (40% word delta).","severity":"risky","descriptionDelta":0.40336134453781514},{"kind":"input_property_added","path":"inputSchema.properties.detachTemplate","tool":"put_automation","after":{"type":"boolean","description":"Only for a flow that still has its template form: true turns it into a canvas-only flow the form can no longer open. Default false."},"detail":"Optional field `detachTemplate` was added to `put_automation`; may shift model behaviour.","severity":"risky"},{"kind":"description_changed","tool":"refresh_account","after":"Re-read one connected channel's metadata. On Naver Blog this re-reads the blog's categories through the user's browser extension and waits up to a minute for it; list_accounts then shows the new list under naverBlog.categories. Call this when a category the person mentions is not in list_accounts yet. If the extension is offline you get 202 and the refresh runs when that browser comes back. Other channels return refresh_unsupported because their metadata is live on every call. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Re-read one connected channel's metadata. On Naver Blog this re-reads the blog's categories through the user's browser extension and waits up to a minute for it; list_accounts then shows the new list under naverBlog.categories. Call this when a category the person mentions is not in list_accounts yet. If the extension is offline you get 202 and the refresh runs when that browser comes back. Other channels return refresh_unsupported because their metadata is live on every call. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `refresh_account` changed (22% word delta).","severity":"safe","descriptionDelta":0.2178217821782178},{"kind":"description_changed","tool":"reply","after":"Reply to a post or to a reply. Leave replyTo empty to reply to the post itself; pass a reply id from list_replies to nest a reply under that reply. Like publish, this returns before the reply is live unless you pass wait: true, which holds the response until it is out (up to 10 seconds). Otherwise call get_post with the returned id to see the final status and link. If the response carries `bridge`, `bridge.nextStep` says what is needed: `run_wake` means Chrome with the extension is closed, so tell the person `bridge.userMessage` with the `bridge.wake` command for their OS and retry once after they say Chrome is open; `ask_user_login` / `ask_user_update` mean tell the person `bridge.userMessage`. Do not retry more than twice.","before":"Reply to a post or to a reply. Leave replyTo empty to reply to the post itself; pass a reply id from list_replies to nest a reply under that reply. Like publish, this returns before the reply is live unless you pass wait: true, which holds the response until it is out (up to 10 seconds). Otherwise call get_post with the returned id to see the final status and link. If the response carries `bridge`, follow `bridge.nextStep`: `run_wake` means run `bridge.wake` for the user's OS if you have a shell on their computer, wait about a minute, call bridge_status, then retry once, otherwise tell the user `bridge.userMessage` as it is; `ask_user_login` / `ask_user_update` mean tell the user `bridge.userMessage`. Do not retry more than twice.","detail":"Description of `reply` changed (27% word delta).","severity":"risky","descriptionDelta":0.27368421052631575},{"kind":"description_changed","tool":"research_naver_keywords","after":"Naver Blog only. Measures keywords (monthly searches from Search Ad, blog document count and posts per month from API HUB), judges each one (best, possible, hard, wall, hot, saturated, phantom and so on, with why), and groups them into sets for one post: a main keyword plus two to five subs with the same search intent. Every set carries prompt, a ready-to-paste Korean brief for writing the skeleton of that post. Up to 60 keywords. Measurements are cached seven days across users; new ones run against a time budget, so partial: true with unmeasured[] means the budget ran out and calling again with the same keywords finishes the rest from cache. Each call is saved as a report (reportId) unless the same keyword set was saved in the last ten minutes, which returns that report's id instead. Every set also carries draftPrompt, a brief for writing the whole post (title, subheadings, body, and bracketed photo placeholders for the person to fill); pass topic to put the post's subject in it. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors. Tell them once and do not call it again until they say it is on.","before":"Naver Blog only. Measures keywords (monthly searches from Search Ad, blog document count and posts per month from API HUB), judges each one (best, possible, hard, wall, hot, saturated, phantom and so on, with why), and groups them into sets for one post: a main keyword plus two to five subs with the same search intent. Every set carries prompt, a ready-to-paste Korean brief for writing the skeleton of that post. Up to 60 keywords. Measurements are cached seven days across users; new ones run against a time budget, so partial: true with unmeasured[] means the budget ran out and calling again with the same keywords finishes the rest from cache. Each call is saved as a report (reportId) unless the same keyword set was saved in the last ten minutes, which returns that report's id instead. Every set also carries draftPrompt, a brief for writing the whole post (title, subheadings, body, and bracketed photo placeholders for the person to fill); pass topic to put the post's subject in it. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors; tell them to open that link.","detail":"Description of `research_naver_keywords` changed (5% word delta).","severity":"safe","descriptionDelta":0.050724637681159424},{"kind":"description_changed","tool":"retry_post","after":"Retry the targets that failed on a publish. Targets that already went out are left alone. Naver Blog caps how many posts one ID publishes; when it does, this returns 429 naver_rate_limited with retryAfterSeconds. Do not call again before that, the draft is already in Naver. Naver Blog asks which form to publish with, every post: if options.naver_blog.form is missing this returns 400 naver_form_required with forms (id, name, when). The form is the house style to use when the person has no style of their own, so read the conversation first. If they dictated the structure or you laid it out yourself, pass options.naver_blog.layout: \"as-is\" and the markdown goes out unchanged. Otherwise show them the forms (naver_layout with forms: \"all\" lays every one out side by side) and call again with the one they pick. Do not pick for them. If a Naver target stopped right after Save as draft (errorCode naver_draft_unknown), this returns 409 naver_draft_unknown and retries nothing; check list_naver_drafts and call again with force: true only if the draft is not there. If a Naver reply did not confirm in time (errorCode naver_reply_unknown), this returns 409 naver_reply_unknown and retries nothing; look at the comment on the blog first and call again with force: true only if the reply is not there. If another post with the same content and files is queued, going out, published or scheduled on the same account, this returns 409 duplicate_post with that post's postId and retries nothing; force: true sends it anyway. If nothing failed you get nothing_to_retry. Only applies to posts published through us. This replays the same payload, so read errorCode and retryable on get_post first: when retryable is false the arguments have to change and you should call publish again instead. On Naver Blog a failed target may still have left a post or a draft in the editor, so check the blog before retrying.","before":"Retry the targets that failed on a publish. Targets that already went out are left alone. Naver Blog caps how many posts one ID publishes; when it does, this returns 429 naver_rate_limited with retryAfterSeconds. Do not call again before that, the draft is already in Naver. Naver Blog asks which form to publish with, every post: if options.naver_blog.form is missing this returns 400 naver_form_required with forms (id, name, when). The form is the house style to use when the person has no style of their own, so read the conversation first. If they dictated the structure or you laid it out yourself, pass options.naver_blog.layout: \"as-is\" and the markdown goes out unchanged. Otherwise show them the forms (naver_layout with forms: \"all\" lays every one out side by side) and call again with the one they pick. Do not pick for them. If nothing failed you get nothing_to_retry. Only applies to posts published through us. This replays the same payload, so read errorCode and retryable on get_post first: when retryable is false the arguments have to change and you should call publish again instead. On Naver Blog a failed target may still have left a post or a draft in the editor, so check the blog before retrying.","detail":"Description of `retry_post` changed (21% word delta).","severity":"safe","descriptionDelta":0.20945945945945943},{"kind":"input_property_added","path":"inputSchema.properties.force","tool":"retry_post","after":{"type":"boolean","description":"Retry even though a Naver target is naver_draft_unknown (pass it only after list_naver_drafts shows the draft is not there) or naver_reply_unknown (pass it only after the comment on the blog shows no such reply), or even though another post with the same content is on the same account (duplicate_post)."},"detail":"Optional field `force` was added to `retry_post`; may shift model behaviour.","severity":"risky"},{"kind":"description_changed","tool":"search_youtube_videos","after":"Searches YouTube for a keyword and returns the top videos with views, subscribers, the views-to-subscribers ratio (above 1 means the title and topic pulled more people than the channel has), Shorts or long-form (60 seconds or less counts as a Short), duration and publish date. order is viewCount, date or relevance; period 7d, 1m, 3m, 6m or 1y; format all, shorts or long; max 1-50 (default 25). The same search is cached 24 hours and does not count; a new one spends one of the person's daily searches (quota in the response) and shared YouTube Data API units (youtube_quota_exhausted when today's are gone). Carries prompt, a Korean brief that turns the table into title and hook ideas; pass topic to fill it in. Saved to the person's search history (reportId). Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors. Tell them once and do not call it again until they say it is on.","before":"Beta. Searches YouTube for a keyword and returns the top videos with views, subscribers, the views-to-subscribers ratio (above 1 means the title and topic pulled more people than the channel has), Shorts or long-form (60 seconds or less counts as a Short), duration and publish date. order is viewCount, date or relevance; period 7d, 1m, 3m, 6m or 1y; format all, shorts or long; max 1-50 (default 25). The same search is cached 24 hours and does not count; a new one spends one of the person's daily searches (quota in the response) and shared YouTube Data API units (youtube_quota_exhausted when today's are gone). Carries prompt, a Korean brief that turns the table into title and hook ideas; pass topic to fill it in. Saved to the person's search history (reportId). Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors; tell them to open that link.","detail":"Description of `search_youtube_videos` changed (8% word delta).","severity":"safe","descriptionDelta":0.08403361344537819},{"kind":"description_changed","tool":"update_post","after":"Change a scheduled or draft post before it goes out, or edit a post that is already live on a channel that supports editing (list_platforms features: today Naver Blog, YouTube and some Facebook posts). Fields: content, mediaIds, accountIds, options, scheduledAt or draft. Fields you leave out keep their current value (on a Naver Blog post, see media below); options you pass replace the whole options object (on a post written directly on the channel they are merged per channel key instead). scheduledAt moves the send time (same rules as publish), null turns it into a draft, and draft: true does the same. A thread (chain) can be changed too while it is scheduled or a draft: content replaces the first item and keeps the later items; threadItems replaces the whole chain (one item collapses it to a single post); passing threadItems to a single post turns it into a chain. Pass id of the first item — later items return 409 thread_piece with rootId. Posts that already went out return post_not_editable on channels that cannot edit a live post. A post written directly on the channel (one a link or id resolved to, origin imported) can be edited on YouTube, on the text of Facebook text, link and photo posts, and on Naver Blog: uplika reads the post from the channel first, so fields you leave out keep the channel's current values. Elsewhere it returns post_not_editable with the reason (list_platforms feature update_imported). A Naver post written in Naver's editor is rewritten from its current source, which uplika reads from Naver's edit screen: text, bold, italic, underline, strikethrough and links are markdown; headings and quotes are markdown only when their text has no style at all; every other block (photos, videos, cards, tables, headings or quotes with a font, and whole text blocks that have colors, sizes or alignment anywhere, several paragraphs each) is one @keep(...) line. A line holding only an invisible U+200B character is blank space at the edge of a text block; leave it to keep the spacing. Send the edited source as content together with sourceVersion. Without it, or when the post changed on Naver since, this returns 409 naver_source_required with the current source and its sourceVersion (get_post also shows sourceVersion, but its content is only the source after uplika has read it once). Keep a @keep line to keep that block where it is, delete it to remove the block; text you write directly next to a @keep text block joins that block, and comes back inside its @keep line on the next read. An unknown id returns 422 naver_keep_unknown. This needs extension 0.7.8 or later (422 extension_outdated otherwise). A published Naver post is rewritten in place (same URL, same logNo) when you pass content, mediaIds or options. On a post that goes only to Naver Blog, the media: references in the new body are the post's media list: when you leave mediaIds out, media the new body does not place is removed from the post and the response note says how many. Pass mediaIds only for media to add at the end of the post without placing it in the body. If the body places more photos or videos than Naver takes (list_platforms), this returns 422 naver_media_over_limit with droppedIds and nothing changes. Naver Blog caps how many posts one ID publishes; when it does, this returns 429 naver_rate_limited with retryAfterSeconds. Do not call again before that, the draft is already in Naver. Naver Blog asks which form to publish with, every post: if options.naver_blog.form is missing this returns 400 naver_form_required with forms (id, name, when). The form is the house style to use when the person has no style of their own, so read the conversation first. If they dictated the structure or you laid it out yourself, pass options.naver_blog.layout: \"as-is\" and the markdown goes out unchanged. Otherwise show them the forms (naver_layout with forms: \"all\" lays every one out side by side) and call again with the one they pick. Do not pick for them. If the Naver editor shows a \"missing image\" error when you open an already-published post for editing, calling update_post on that post rewrites it in place and fixes it; the URL stays the same. A Naver draft (a target whose externalId starts with draft:, from options.naver_blog.draftOnly) is not on the blog: update_post publishes uplika's copy as a new post and, with extension 0.7.2 or later, removes the old draft from Naver's draft box. To publish the draft exactly as it is in Naver, call publish_naver_draft. Editing a post that is already live is asynchronous: pass wait: true to hold the response for the result (up to 75 seconds), or read it with get_post.","before":"Change a scheduled or draft post before it goes out, or edit a post that is already live on a channel that supports editing (list_platforms features: today Naver Blog, YouTube and some Facebook posts). Fields: content, mediaIds, accountIds, options, scheduledAt or draft. Fields you leave out keep their current value; options you pass replace the whole options object. scheduledAt moves the send time (same rules as publish), null turns it into a draft, and draft: true does the same. A thread (chain) can be changed too while it is scheduled or a draft: content replaces the first item and keeps the later items; threadItems replaces the whole chain (one item collapses it to a single post); passing threadItems to a single post turns it into a chain. Pass id of the first item — later items return 409 thread_piece with rootId. Posts that already went out return post_not_editable on channels that cannot edit a live post. A published Naver post is rewritten in place (same URL, same logNo) when you pass content, mediaIds or options — list the media ids again to keep the photos. Naver Blog caps how many posts one ID publishes; when it does, this returns 429 naver_rate_limited with retryAfterSeconds. Do not call again before that, the draft is already in Naver. Naver Blog asks which form to publish with, every post: if options.naver_blog.form is missing this returns 400 naver_form_required with forms (id, name, when). The form is the house style to use when the person has no style of their own, so read the conversation first. If they dictated the structure or you laid it out yourself, pass options.naver_blog.layout: \"as-is\" and the markdown goes out unchanged. Otherwise show them the forms (naver_layout with forms: \"all\" lays every one out side by side) and call again with the one they pick. Do not pick for them. If the Naver editor shows a \"missing image\" error when you open an already-published post for editing, calling update_post on that post rewrites it in place and fixes it; the URL stays the same. A Naver draft (a target whose externalId starts with draft:, from options.naver_blog.draftOnly) is not on the blog: update_post publishes uplika's copy as a new post and, with extension 0.7.2 or later, removes the old draft from Naver's draft box. To publish the draft exactly as it is in Naver, call publish_naver_draft.","detail":"Description of `update_post` changed (38% word delta).","severity":"risky","descriptionDelta":0.3771626297577855},{"kind":"input_property_added","path":"inputSchema.properties.sourceVersion","tool":"update_post","after":{"type":"string","description":"Only for a Naver post written in Naver's editor: the sourceVersion that came with the source you edited (from naver_source_required or get_post). It tells uplika the content was made from the post's current source."},"detail":"Optional field `sourceVersion` was added to `update_post`; may shift model behaviour.","severity":"risky"},{"kind":"input_property_added","path":"inputSchema.properties.wait","tool":"update_post","after":{"type":"boolean","description":"Only when editing a post that is already live: hold the response until the edit has gone through or not, up to 75 seconds. Past that it returns while still working, with next telling you to read get_post."},"detail":"Optional field `wait` was added to `update_post`; may shift model behaviour.","severity":"risky"}],"published_at":"2026-10-04T04:42:17.156Z"},{"slug":"ZV-2026-1417","server_name":"api.uplika.com","severity":"breaking","title":"api.uplika.com: Field photos was removed from research_naver_keywords input; consumers still sending it may be rejected or silently ignored.","summary":"[safe] Description of research_naver_keywords changed (4% word delta). [breaking] Field photos was removed from research_naver_keywords input; consumers still sending it may be rejected or silently ignored.","changes":[{"kind":"description_changed","tool":"research_naver_keywords","after":"Naver Blog only. Measures keywords (monthly searches from Search Ad, blog document count and posts per month from API HUB), judges each one (best, possible, hard, wall, hot, saturated, phantom and so on, with why), and groups them into sets for one post: a main keyword plus two to five subs with the same search intent. Every set carries prompt, a ready-to-paste Korean brief for writing the skeleton of that post. Up to 60 keywords. Measurements are cached seven days across users; new ones run against a time budget, so partial: true with unmeasured[] means the budget ran out and calling again with the same keywords finishes the rest from cache. Each call is saved as a report (reportId) unless the same keyword set was saved in the last ten minutes, which returns that report's id instead. Every set also carries draftPrompt, a brief for writing the whole post (title, subheadings, body, and [사진: …] photo slots for the person to fill); pass topic to put the post's subject in it. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors; tell them to open that link.","before":"Naver Blog only. Measures keywords (monthly searches from Search Ad, blog document count and posts per month from API HUB), judges each one (best, possible, hard, wall, hot, saturated, phantom and so on, with why), and groups them into sets for one post: a main keyword plus two to five subs with the same search intent. Every set carries prompt, a ready-to-paste Korean brief for writing the skeleton of that post. Up to 60 keywords. Measurements are cached seven days across users; new ones run against a time budget, so partial: true with unmeasured[] means the budget ran out and calling again with the same keywords finishes the rest from cache. Each call is saved as a report (reportId) unless the same keyword set was saved in the last ten minutes, which returns that report's id instead. Every set also carries draftPrompt, a brief for writing the whole post (title, subheadings, body, photo placement); pass topic and photos to fill it in. Returns 403 research_tool_disabled with enableUrl if the person has not turned this tool on for connectors; tell them to open that link.","detail":"Description of `research_naver_keywords` changed (4% word delta).","severity":"safe","descriptionDelta":0.03731343283582089},{"kind":"input_property_removed","path":"inputSchema.properties.photos","tool":"research_naver_keywords","before":{"type":"array","items":{"type":"string"},"description":"One line per photo saying what it shows, in order. draftPrompt places them; a placeholder otherwise."},"detail":"Field `photos` was removed from `research_naver_keywords` input; consumers still sending it may be rejected or silently ignored.","severity":"breaking"}],"published_at":"2026-09-24T18:32:18.435Z"}]