Answer Updates
News moves fast. A question from last week can have a better answer today. Answer Updates let a reader subscribe to a conversation. Miso watches that topic, appends a fresh follow-up answer when it finds important new content, and raises an indicator your interface can show.
This builds on User History — a thread has to exist before a reader can subscribe to it. Read that page first.
History is enabled per app. Miso records a question in history only for apps that have the feature switched on. On an app without it,
POST /v1/ask/user_historyreturns an empty list, andsubscribeanswers404 "Thread not found"— the thread it looks for was never recorded. Ask your Miso representative to enable it before you build against these endpoints.
News moves fast. A question from last week can have a better answer today. Answer Updates let a reader subscribe to a conversation. Miso then watches that topic. When Miso finds important new content, it appends a fresh follow-up answer to the thread and raises a notification.
Two levels of unread indicator
Miso reports two booleans. Most interfaces render them as a dot or a badge, but the API only tells you whether an unseen update exists.
| Indicator | Question it answers | How you read it |
|---|---|---|
| Account level | Does this user have any unseen update? | Poll POST /v1/ask/user_history/thread/updates |
| Thread level | Does this thread have an unseen update? | The has_new field on the history list |
Miso calculates both values at read time. It compares the time of the last update with the time the user last dismissed that level. Miso does not store a separate flag.
Every endpoint, and what it returns
Each call takes user_id, and the per-thread calls also take thread_id (the
root question of the thread). These are the exact bodies, from a live run:
| Endpoint | Body | Response |
|---|---|---|
…/thread/updates |
user_id |
{"message": "success", "data": {"has_new": false}} |
…/thread/updates/subscribe |
user_id, thread_id |
{"message": "success"}, or 404 {"message": "Thread not found"} |
…/thread/updates/unsubscribe |
user_id, thread_id |
{"message": "success"}. Idempotent. |
…/thread/updates/dismiss_thread |
user_id, thread_id |
{"message": "success"}. Idempotent. |
…/thread/updates/dismiss_overall |
user_id |
{"message": "success"} |
…/thread/updates/touch |
user_id, thread_id |
{"message": "success", "data": {"touched": 0}} |
Only two calls return a data object. The poll returns has_new, and touch
returns touched — the number of subscriptions it stamped. touched: 0
means no live subscription matches, so nothing lights up. Use it to check your
test setup before you blame the front end.
With generate: true, touch also writes the update, and names it:
{
"message": "success",
"data": {
"generated": true,
"question_id": "c925d60f-bf71-47b7-992e-9c732f2a34d3",
"touched": 1
}
}
That question_id is a new turn at the end of the thread. Read it with the
single-answer endpoint, the same way you read any other turn.
Every one of these requires user_id. Without it you get
400 {"message": "user_id is required"}.
Subscribe a thread
POST /v1/ask/user_history/thread/updates/subscribe
| Field | Type | Notes |
|---|---|---|
user_id |
string | The subscriber. |
thread_id |
UUID | The thread's root question id. |
This call is idempotent. If the user does not own the thread, Miso returns
404.
Unsubscribe
Subscribe answers 404 "Thread not found" when that thread_id is not a
thread of that user_id. Two causes, in this order: history is not enabled for
the app, or the user_id does not match the one that asked the question.
POST /v1/ask/user_history/thread/updates/unsubscribe uses the same body
(user_id, thread_id). This call is idempotent.
Poll the account-level indicator
POST /v1/ask/user_history/thread/updates takes the body user_id. Your UI
polls this endpoint to show or clear the account-level indicator, for example
every 60 seconds.
{
"data": {
"has_new": true
}
}
Dismiss
| Endpoint | Body | Effect |
|---|---|---|
…/thread/updates/dismiss_thread |
user_id, thread_id |
Clears one thread. If no other thread has an unseen update, the account-level indicator clears too. |
…/thread/updates/dismiss_overall |
user_id |
Clears the account-level indicator only. Each thread keeps its own. |
How each value is decided:
thread has_new = an update arrived after you last dismissed that thread
account has_new = some subscribed, visible thread has an unseen update
that is newer than your last "dismiss all"
If the user dismisses every thread, the account-level indicator clears on its
own. dismiss_overall clears only the account level. Each thread keeps its own
indicator for the user to review.
How updates are generated
- Miso monitors subscribed threads periodically, not on every request. By default, a thread produces at most one generated update per day.
- Miso counts only content published after the thread's last activity as an update. Older articles can appear only as clearly-labeled background.
- Miso judges the importance of the content before it appends. If nothing important is new, Miso creates no update and no indicator.
-
Generation is asynchronous. The new follow-up answer streams like any other
answer. To read it, reopen the thread or fetch the new
question_id. - Miso titles the follow-up like "Latest developments since July 7, 2026 regarding: <thread title>".
What a generated update looks like
Miso writes the question for the reader, from the thread's title. A subscribed thread titled "Rocky Linux" produces a turn like this:
{
"question": "Latest developments since July 31, 2026 regarding: Rocky Linux",
"metadata": {
"miso_generated_by": "answer_update_monitor"
},
"answer": "There are no new updates on Rocky Linux in the knowledge base since July 31, 2026. This topic will continue to be monitored for any future developments."
}
Two things follow. Renaming a thread changes the wording of its later updates, because the title is the subject. And an update is written even when there is nothing new, so the reader can see that the topic was checked. Show the indicator, and let them read the turn.
Telling a generated update from a reader's question
A generated update is appended to the thread as an ordinary follow-up, so
parent_question_id does not separate the two — both have one.
Miso marks every generated update instead. Read the answer and check
metadata:
{
"data": {
"question_id": "7c8d9e0f-1a2b-3c4d-5e6f-7a8b9c0d1e2f",
"question": "Latest developments since July 7, 2026 regarding: …",
"answer": "…",
"metadata": {
"miso_generated_by": "answer_update_monitor"
}
}
}
A question the reader typed carries no such key.
const isGeneratedUpdate = (answer) =>
answer.metadata?.miso_generated_by === "answer_update_monitor";
The key appears on both routes that create an update: the automatic monitor,
and touch with generate: true. It reaches you through the single-answer
poll and through the bulk /v1/ask/answers endpoint.
This is an origin hint, not a security boundary.
metadatais client-writable, so a caller can send the same key on a typed question. That misleads only that caller's own interface, and it grants no extra access. Do not use it to gate anything.
Trigger an update on demand (advanced, server-side)
POST /v1/ask/user_history/thread/updates/touch
This endpoint is optional. It marks a thread's subscriptions as updated now. Use it for server-side integrations and end-to-end tests.
| Field | Type | Notes |
|---|---|---|
thread_id |
UUID | The thread to mark as updated. |
user_id |
string | Optional (secret key). Narrows the change to one subscriber. |
generate |
boolean | If true, also appends a generated follow-up answer. |
-
Secret key: marks every live subscription of the thread. The
user_idfield narrows the change to one subscriber. - Publishable key: limited to the caller's own subscription. You can light set the indicator only for yourself.
-
The API key determines the
app_id. As a result, a key can mark only the threads of its own app.
{
"data": {
"generated": true,
"question_id": "…",
"touched": 1
}
}
CAUTION:
touchappends and stamps without any check. If the thread has no new content,generate: trueproduces a sourceless "no new updates" card. The automatic monitor judges the content first and never does this. Use subscriptions for the real user experience. Usetouchonly for tests or explicit server-side triggers.
Putting it together
-
On load — poll
…/thread/updatesfor the account-level indicator, and read each thread'shas_newfrom the history list. -
Open a thread — fetch it, then call
…/dismiss_threadto clear that thread's indicator. -
Offer updates — call
…/subscribeon the threads a reader cares about, and keep polling for fresh answers. -
Tell the two apart — check
metadata.miso_generated_bybefore you render a turn as the reader's own question.
