Skip to content
Charming Docs
Esc
navigateopen⌘Jpreview

Subscribe to the live-state SSE stream for an app

Server-Sent Events stream of state-changed notifications. Each event id is <server-epoch>:<rev>; the browser EventSource replays via Last-Event-ID on reconnect, and the server emits a synthetic state-changed event with source: "reconnect-resync" and result: null whenever the client’s id belongs to an older epoch or claims an unseen revision. The overcapacity event is emitted (and the stream closed) when the per-app subscriber cap is reached. Heartbeats are SSE comment lines (: ping) every 15s.

Auth posture is broader than the owner endpoints: appToken, userToken, renderToken (bearer or ?t= query), or the path-scoped buildy_sse_<id> HMAC cookie minted by the /app/{id} render-bridge when a render-token rendered the page. The {} (no-auth) option in security covers the cookie path — OpenAPI cannot model a per-app cookie name as a fixed scheme.

GET/app/{id}/events
Authorization

Optional — this operation also accepts unauthenticated requests.

AuthorizationBearer token (bld_app_*) · header
Per-app token returned once by `POST /app` for anonymous creates. Authorises mutations and `/api/*` calls on that one app only.
or
AuthorizationBearer token (bld_user_*) · header
User-scoped personal access token. Mint via `POST /api/token` after signing in, or via the device-pairing flow at `POST /api/pair/start`. Authorises everything the user can do.
or
AuthorizationBearer token (bld_render_*) · header
Short-lived per-app token used by null-origin sandboxed iframes (Claude Desktop, ChatGPT Apps) to call back into the app without cookies. Minted server-side at render time and embedded in the runtime closure; not user-mintable. Bound to one app id.
or
tAPI key · query
URL-signed render token, equivalent to `renderToken` but carried in the query string for GET /app/{id} loads where iframes cannot attach Authorization headers (the MCP viewer fetch+srcdoc path). Bound to one app id; expires after ~24 hours.
Path parameters
idstringrequired
Query parameters
tstring
URL-signed render token, equivalent to the `renderToken` bearer but carried in the query string for SSE connections from null-origin iframes that cannot attach Authorization headers.
Header parameters
Last-Event-IDstring
Last event id the client saw, in the `<epoch>:<rev>` form the server emits. Triggers a synthetic `reconnect-resync` event when the epoch differs or the rev is forward-jumped.
Responses
200Open SSE stream. Frames arrive as `event: state-changed` (or `event: overcapacity`) with a JSON `data:` payload. The stream stays open until the client disconnects, the per-app capacity cap is hit, or the server shuts down.
One of:
AppEventStateChanged
kindstringrequired
Allowed:state-changed
appIdstringrequired
opstring | nullrequired
Operation name that produced the state change, or `null` on synthetic `reconnect-resync` events.
sourcestringrequired
`agent` for writes routed through the runtime; `reconnect-resync` for the server-generated catch-up signal.
Allowed:agentreconnect-resync
tsintegerrequired
Unix milliseconds at the time the frame was written.
resultanyrequired
Operation result body when JSON-shaped, `null` on `reconnect-resync` events and on operations whose response was non-JSON or exceeded the 32 KiB cap.
AppEventOvercapacity
messagestringrequired
Allowed:too_many_subscribers
400Invalid app id. Error kind: `invalid_id`.
okbooleanrequired
Allowed:false
errorobjectrequired
Show properties
kindstringrequired
Stable enum-shaped error key. Branch on this for recovery flows.
Allowed:not_foundunknown_operationoperation_not_foundoperation_failedunauthorizedtoken_expiredforbiddenforbidden_writestorage_quota_exceededinvalid_moduleinvalid_uiinvalid_route_schemainvalid_routes_shapeinvalid_manifest_exportsinvalid_requestinvalid_inputinvalid_outputunexpected_keyscapability_deniedcapability_errorexecutor_errorinvalid_call_shapealready_claimedduplicate_remixmanifest_not_foundpayload_too_largemodule_too_largeui_too_largedescription_too_longmissing_descriptioninvalid_descriptionrate_limitedtoo_many_requestsexpiredalready_approvedanon_not_remixableinvalid_if_matchprecondition_requiredversion_mismatchold_string_not_foundold_string_not_uniqueedits_too_largemanifest_id_conflictmanifest_id_immutabletext_too_largestructured_data_too_largeapp_not_foundasset_too_largeasset_count_exceededasset_quota_exceededasset_invalid_keyasset_invalid_content_typeasset_errorinvalid_idsse_cookie_expiredinvalid_secret_namesecret_too_largesecret_already_existsinvalid_iconteam_slug_takenalready_membergrantee_not_foundinvite_cap_reachedread_onlyhandle_takeninvalid_handlename_takenapp_unclaimedlink_cap_reachedgrantee_is_owneralready_invited
messagestring
reasonstring
Set on 401s to distinguish token failure modes when finer detail is needed. `token_revoked_post_claim` is the post-#1284 surface for a bld_app_* that was invalidated by a claim — the `recovery` field on the same `error` object carries the self-contained pairing-recovery hint the agent should follow instead of creating a new app.
Allowed:token_malformedtoken_unknowntoken_revokedtoken_revoked_post_claim
recoveryRecoveryPair | RecoveryRetry | RecoveryShrink | RecoveryRefetch | RecoveryFixRouteLabel | RecoveryOpenExisting | RecoveryRename
Self-contained recovery hint, branching on `kind`. Attached to error envelopes the agent can self-correct on: `pair` for `token_revoked_post_claim` 401s (#1284), `retry` for 429s, `shrink` for too-large / quota-exceeded 413s, `refetch` for 412 `version_mismatch` / `invalid_if_match` / 428 `precondition_required`, `fix_route_label` for 403 `forbidden_write`, `open_existing` for 409 `duplicate_remix`, and `rename` for 409 `manifest_id_immutable` / `manifest_id_conflict`. Every `instructions` string is a single-paragraph, action-first walk-through. Inlined per ADR 2026-05-06-agent-facing-error-surfaces-self-contain-the-fix.
Show properties
One of:
RecoveryPair
kindstringrequired
Allowed:pair
startstring<uri>required
verification_urlstring<uri>required
instructionsstringrequired
RecoveryRetry
kindstringrequired
Allowed:retry
retry_after_secintegerrequired
Seconds to wait before retrying. Matches the `RateLimit-Reset` and `Retry-After` headers on the same response.
min 0
retry_after_urlstring<uri>required
Absolute URL to retry verbatim once the wait elapses.
instructionsstringrequired
RecoveryShrink
kindstringrequired
Allowed:shrink
fieldstringrequired
Which input tripped the cap.
Allowed:moduleuistylesdescriptiontextstructured_dataasseteditssecretpayload
size_bytesintegerrequired
min 0
cap_bytesintegerrequired
min 0
instructionsstringrequired
RecoveryRefetch
kindstringrequired
Allowed:refetch
refetch_urlstring<uri>required
Absolute URL to GET for the fresh ETag before retrying with a corrected If-Match.
instructionsstringrequired
RecoveryFixRouteLabel
kindstringrequired
Allowed:fix_route_label
instructionsstringrequired
App-code recovery: the fix is in the route declaration, NOT in the request. Retrying the same request will fail again.
RecoveryOpenExisting
kindstringrequired
Allowed:open_existing
existing_app_idstringrequired
existing_urlstring<uri>required
instructionsstringrequired
RecoveryRename
kindstringrequired
Allowed:rename
instructionsstringrequired
401Anonymous caller's `buildy_sse_<id>` cookie was once valid but its 1-hour TTL elapsed. Error kind: `sse_cookie_expired` — reload `/app/{id}` so the render-token bridge re-issues a fresh cookie.
okbooleanrequired
Allowed:false
errorobjectrequired
Show properties
kindstringrequired
Stable enum-shaped error key. Branch on this for recovery flows.
Allowed:not_foundunknown_operationoperation_not_foundoperation_failedunauthorizedtoken_expiredforbiddenforbidden_writestorage_quota_exceededinvalid_moduleinvalid_uiinvalid_route_schemainvalid_routes_shapeinvalid_manifest_exportsinvalid_requestinvalid_inputinvalid_outputunexpected_keyscapability_deniedcapability_errorexecutor_errorinvalid_call_shapealready_claimedduplicate_remixmanifest_not_foundpayload_too_largemodule_too_largeui_too_largedescription_too_longmissing_descriptioninvalid_descriptionrate_limitedtoo_many_requestsexpiredalready_approvedanon_not_remixableinvalid_if_matchprecondition_requiredversion_mismatchold_string_not_foundold_string_not_uniqueedits_too_largemanifest_id_conflictmanifest_id_immutabletext_too_largestructured_data_too_largeapp_not_foundasset_too_largeasset_count_exceededasset_quota_exceededasset_invalid_keyasset_invalid_content_typeasset_errorinvalid_idsse_cookie_expiredinvalid_secret_namesecret_too_largesecret_already_existsinvalid_iconteam_slug_takenalready_membergrantee_not_foundinvite_cap_reachedread_onlyhandle_takeninvalid_handlename_takenapp_unclaimedlink_cap_reachedgrantee_is_owneralready_invited
messagestring
reasonstring
Set on 401s to distinguish token failure modes when finer detail is needed. `token_revoked_post_claim` is the post-#1284 surface for a bld_app_* that was invalidated by a claim — the `recovery` field on the same `error` object carries the self-contained pairing-recovery hint the agent should follow instead of creating a new app.
Allowed:token_malformedtoken_unknowntoken_revokedtoken_revoked_post_claim
recoveryRecoveryPair | RecoveryRetry | RecoveryShrink | RecoveryRefetch | RecoveryFixRouteLabel | RecoveryOpenExisting | RecoveryRename
Self-contained recovery hint, branching on `kind`. Attached to error envelopes the agent can self-correct on: `pair` for `token_revoked_post_claim` 401s (#1284), `retry` for 429s, `shrink` for too-large / quota-exceeded 413s, `refetch` for 412 `version_mismatch` / `invalid_if_match` / 428 `precondition_required`, `fix_route_label` for 403 `forbidden_write`, `open_existing` for 409 `duplicate_remix`, and `rename` for 409 `manifest_id_immutable` / `manifest_id_conflict`. Every `instructions` string is a single-paragraph, action-first walk-through. Inlined per ADR 2026-05-06-agent-facing-error-surfaces-self-contain-the-fix.
Show properties
One of:
RecoveryPair
kindstringrequired
Allowed:pair
startstring<uri>required
verification_urlstring<uri>required
instructionsstringrequired
RecoveryRetry
kindstringrequired
Allowed:retry
retry_after_secintegerrequired
Seconds to wait before retrying. Matches the `RateLimit-Reset` and `Retry-After` headers on the same response.
min 0
retry_after_urlstring<uri>required
Absolute URL to retry verbatim once the wait elapses.
instructionsstringrequired
RecoveryShrink
kindstringrequired
Allowed:shrink
fieldstringrequired
Which input tripped the cap.
Allowed:moduleuistylesdescriptiontextstructured_dataasseteditssecretpayload
size_bytesintegerrequired
min 0
cap_bytesintegerrequired
min 0
instructionsstringrequired
RecoveryRefetch
kindstringrequired
Allowed:refetch
refetch_urlstring<uri>required
Absolute URL to GET for the fresh ETag before retrying with a corrected If-Match.
instructionsstringrequired
RecoveryFixRouteLabel
kindstringrequired
Allowed:fix_route_label
instructionsstringrequired
App-code recovery: the fix is in the route declaration, NOT in the request. Retrying the same request will fail again.
RecoveryOpenExisting
kindstringrequired
Allowed:open_existing
existing_app_idstringrequired
existing_urlstring<uri>required
instructionsstringrequired
RecoveryRename
kindstringrequired
Allowed:rename
instructionsstringrequired
403Caller does not have access to this app.
okbooleanrequired
Allowed:false
errorobjectrequired
Show properties
kindstringrequired
Stable enum-shaped error key. Branch on this for recovery flows.
Allowed:not_foundunknown_operationoperation_not_foundoperation_failedunauthorizedtoken_expiredforbiddenforbidden_writestorage_quota_exceededinvalid_moduleinvalid_uiinvalid_route_schemainvalid_routes_shapeinvalid_manifest_exportsinvalid_requestinvalid_inputinvalid_outputunexpected_keyscapability_deniedcapability_errorexecutor_errorinvalid_call_shapealready_claimedduplicate_remixmanifest_not_foundpayload_too_largemodule_too_largeui_too_largedescription_too_longmissing_descriptioninvalid_descriptionrate_limitedtoo_many_requestsexpiredalready_approvedanon_not_remixableinvalid_if_matchprecondition_requiredversion_mismatchold_string_not_foundold_string_not_uniqueedits_too_largemanifest_id_conflictmanifest_id_immutabletext_too_largestructured_data_too_largeapp_not_foundasset_too_largeasset_count_exceededasset_quota_exceededasset_invalid_keyasset_invalid_content_typeasset_errorinvalid_idsse_cookie_expiredinvalid_secret_namesecret_too_largesecret_already_existsinvalid_iconteam_slug_takenalready_membergrantee_not_foundinvite_cap_reachedread_onlyhandle_takeninvalid_handlename_takenapp_unclaimedlink_cap_reachedgrantee_is_owneralready_invited
messagestring
reasonstring
Set on 401s to distinguish token failure modes when finer detail is needed. `token_revoked_post_claim` is the post-#1284 surface for a bld_app_* that was invalidated by a claim — the `recovery` field on the same `error` object carries the self-contained pairing-recovery hint the agent should follow instead of creating a new app.
Allowed:token_malformedtoken_unknowntoken_revokedtoken_revoked_post_claim
recoveryRecoveryPair | RecoveryRetry | RecoveryShrink | RecoveryRefetch | RecoveryFixRouteLabel | RecoveryOpenExisting | RecoveryRename
Self-contained recovery hint, branching on `kind`. Attached to error envelopes the agent can self-correct on: `pair` for `token_revoked_post_claim` 401s (#1284), `retry` for 429s, `shrink` for too-large / quota-exceeded 413s, `refetch` for 412 `version_mismatch` / `invalid_if_match` / 428 `precondition_required`, `fix_route_label` for 403 `forbidden_write`, `open_existing` for 409 `duplicate_remix`, and `rename` for 409 `manifest_id_immutable` / `manifest_id_conflict`. Every `instructions` string is a single-paragraph, action-first walk-through. Inlined per ADR 2026-05-06-agent-facing-error-surfaces-self-contain-the-fix.
Show properties
One of:
RecoveryPair
kindstringrequired
Allowed:pair
startstring<uri>required
verification_urlstring<uri>required
instructionsstringrequired
RecoveryRetry
kindstringrequired
Allowed:retry
retry_after_secintegerrequired
Seconds to wait before retrying. Matches the `RateLimit-Reset` and `Retry-After` headers on the same response.
min 0
retry_after_urlstring<uri>required
Absolute URL to retry verbatim once the wait elapses.
instructionsstringrequired
RecoveryShrink
kindstringrequired
Allowed:shrink
fieldstringrequired
Which input tripped the cap.
Allowed:moduleuistylesdescriptiontextstructured_dataasseteditssecretpayload
size_bytesintegerrequired
min 0
cap_bytesintegerrequired
min 0
instructionsstringrequired
RecoveryRefetch
kindstringrequired
Allowed:refetch
refetch_urlstring<uri>required
Absolute URL to GET for the fresh ETag before retrying with a corrected If-Match.
instructionsstringrequired
RecoveryFixRouteLabel
kindstringrequired
Allowed:fix_route_label
instructionsstringrequired
App-code recovery: the fix is in the route declaration, NOT in the request. Retrying the same request will fail again.
RecoveryOpenExisting
kindstringrequired
Allowed:open_existing
existing_app_idstringrequired
existing_urlstring<uri>required
instructionsstringrequired
RecoveryRename
kindstringrequired
Allowed:rename
instructionsstringrequired
404App not found.
okbooleanrequired
Allowed:false
errorobjectrequired
Show properties
kindstringrequired
Stable enum-shaped error key. Branch on this for recovery flows.
Allowed:not_foundunknown_operationoperation_not_foundoperation_failedunauthorizedtoken_expiredforbiddenforbidden_writestorage_quota_exceededinvalid_moduleinvalid_uiinvalid_route_schemainvalid_routes_shapeinvalid_manifest_exportsinvalid_requestinvalid_inputinvalid_outputunexpected_keyscapability_deniedcapability_errorexecutor_errorinvalid_call_shapealready_claimedduplicate_remixmanifest_not_foundpayload_too_largemodule_too_largeui_too_largedescription_too_longmissing_descriptioninvalid_descriptionrate_limitedtoo_many_requestsexpiredalready_approvedanon_not_remixableinvalid_if_matchprecondition_requiredversion_mismatchold_string_not_foundold_string_not_uniqueedits_too_largemanifest_id_conflictmanifest_id_immutabletext_too_largestructured_data_too_largeapp_not_foundasset_too_largeasset_count_exceededasset_quota_exceededasset_invalid_keyasset_invalid_content_typeasset_errorinvalid_idsse_cookie_expiredinvalid_secret_namesecret_too_largesecret_already_existsinvalid_iconteam_slug_takenalready_membergrantee_not_foundinvite_cap_reachedread_onlyhandle_takeninvalid_handlename_takenapp_unclaimedlink_cap_reachedgrantee_is_owneralready_invited
messagestring
reasonstring
Set on 401s to distinguish token failure modes when finer detail is needed. `token_revoked_post_claim` is the post-#1284 surface for a bld_app_* that was invalidated by a claim — the `recovery` field on the same `error` object carries the self-contained pairing-recovery hint the agent should follow instead of creating a new app.
Allowed:token_malformedtoken_unknowntoken_revokedtoken_revoked_post_claim
recoveryRecoveryPair | RecoveryRetry | RecoveryShrink | RecoveryRefetch | RecoveryFixRouteLabel | RecoveryOpenExisting | RecoveryRename
Self-contained recovery hint, branching on `kind`. Attached to error envelopes the agent can self-correct on: `pair` for `token_revoked_post_claim` 401s (#1284), `retry` for 429s, `shrink` for too-large / quota-exceeded 413s, `refetch` for 412 `version_mismatch` / `invalid_if_match` / 428 `precondition_required`, `fix_route_label` for 403 `forbidden_write`, `open_existing` for 409 `duplicate_remix`, and `rename` for 409 `manifest_id_immutable` / `manifest_id_conflict`. Every `instructions` string is a single-paragraph, action-first walk-through. Inlined per ADR 2026-05-06-agent-facing-error-surfaces-self-contain-the-fix.
Show properties
One of:
RecoveryPair
kindstringrequired
Allowed:pair
startstring<uri>required
verification_urlstring<uri>required
instructionsstringrequired
RecoveryRetry
kindstringrequired
Allowed:retry
retry_after_secintegerrequired
Seconds to wait before retrying. Matches the `RateLimit-Reset` and `Retry-After` headers on the same response.
min 0
retry_after_urlstring<uri>required
Absolute URL to retry verbatim once the wait elapses.
instructionsstringrequired
RecoveryShrink
kindstringrequired
Allowed:shrink
fieldstringrequired
Which input tripped the cap.
Allowed:moduleuistylesdescriptiontextstructured_dataasseteditssecretpayload
size_bytesintegerrequired
min 0
cap_bytesintegerrequired
min 0
instructionsstringrequired
RecoveryRefetch
kindstringrequired
Allowed:refetch
refetch_urlstring<uri>required
Absolute URL to GET for the fresh ETag before retrying with a corrected If-Match.
instructionsstringrequired
RecoveryFixRouteLabel
kindstringrequired
Allowed:fix_route_label
instructionsstringrequired
App-code recovery: the fix is in the route declaration, NOT in the request. Retrying the same request will fail again.
RecoveryOpenExisting
kindstringrequired
Allowed:open_existing
existing_app_idstringrequired
existing_urlstring<uri>required
instructionsstringrequired
RecoveryRename
kindstringrequired
Allowed:rename
instructionsstringrequired
Request
curl -X GET "https://charm.ing/app/string/events" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "kind": "state-changed",
  "appId": "string",
  "op": "string",
  "source": "agent",
  "ts": 0,
  "result": "string"
}