Console API
Website modifications
16 endpoints.
/api/v1/admin/businesses/{business_id}/website-modRead the business's website-mod thread, pending change and preview
The Changes tab's whole read, in one call.
``publishable`` answers the only question the tab's button needs: there is a change awaiting approval, it belongs to this console thread, and both the run id and the approval bundle ref needed to approve it are known.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Responses
200Successful Responseapplication/jsonSuccessResponse_WebsiteModStateResponse_| Field | Type | Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
request_idrequired | string | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
success | true | default true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
datarequired | WebsiteModStateResponse | WebsiteModStateResponse fields
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
metadata | ResponseMetadata | null | ResponseMetadata fields
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
meta | ResponseMeta | null | ResponseMeta fields
|
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/cancelCancel the pending website change
Drive the run to completion, THEN clear pending, close the PR, unlock.
Order is the fix for a live bug: cleanup-first left the parked Temporal workflow squatting on the thread's workflow id whenever the reject could not be delivered (a change discarded mid-planning has no approval bundle to reject), and the next submit — with every sor gate now green — hit the engine's raw TEMPORAL_START_FAILED. The unwind now runs FIRST and fails LOUDLY: on failure nothing has been cleared, the pending change is still visible, and the cancel can simply be retried. Only once a completion lever is armed (reject delivered, workflow already gone, or the run tombstoned so the plan surface terminates it) does the local cleanup run — idempotent with the engine's own reject-path cleanup.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Request body
application/jsonWebsiteModCancelBody | null| Field | Type | Description |
|---|---|---|
comment | string | null |
Responses
200Successful Responseapplication/jsonSuccessResponse_WebsiteModCancelResponse_| Field | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
request_idrequired | string | |||||||||||||||||||
success | true | default true | ||||||||||||||||||
datarequired | WebsiteModCancelResponse | WebsiteModCancelResponse fields
| ||||||||||||||||||
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. | ||||||||||||||||||
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/changesSubmit a website change request from the console
202: the request is recorded on the thread and a run is started on it.
The run then drives the unchanged pipeline — plan-and-open-pr, preview polling, the approval gate this tab's Publish answers, merge-deploy — so the console never has to reimplement any stage of it. Poll the GET for the pending change and the preview URL.
``text`` still rides along as the run's ``user_message`` input (the workflow reads it); it is ALSO written to the thread, because an input is not a record — before that, a reload lost the operator's own words.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Request bodyrequired
application/jsonWebsiteModChangeBody| Field | Type | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
textrequired | string | null | ||||||||||
client_message_id | string | null | ||||||||||
model_id | string | null | ||||||||||
attachments | WebsiteAgentAttachmentRef[] | max items 10WebsiteAgentAttachmentRef[] fields
| |||||||||
delivery | enum | null |
Responses
202Successful Responseapplication/jsonSuccessResponse_WebsiteModChangeResponse_| Field | Type | Description | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
request_idrequired | string | |||||||||||||||||||||||||
success | true | default true | ||||||||||||||||||||||||
datarequired | WebsiteModChangeResponse | WebsiteModChangeResponse fields
| ||||||||||||||||||||||||
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. | ||||||||||||||||||||||||
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/check/overrideLet a change its browser check holds back be published (Keystone staff)
Keystone staff only: the reason and what the check had found are kept in ``website_check_overrides``. 409 when nothing is held back.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Request bodyrequired
application/jsonBrowserCheckOverrideBody| Field | Type | Description |
|---|---|---|
reasonrequired | string | min length 10 · max length 1000 |
Responses
200Successful Responseapplication/jsonSuccessResponse_BrowserCheckView_| Field | Type | Description |
|---|---|---|
request_idrequired | string | |
success | true | default true |
datarequired | BrowserCheckView | BrowserCheckView fieldsBrowserCheckView, expanded above. |
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. |
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/check/recheckLook at the pending change's pages in a browser again
202: the session pod looks again, without the site agent, at the pages a check that never reached the browser was to look at. The state read shows ``rechecking`` until the new check lands. 409 for a check a look cannot settle (problems the agent saw), or while the agent works.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Responses
202Successful Responseapplication/jsonSuccessResponse_BrowserCheckView_| Field | Type | Description |
|---|---|---|
request_idrequired | string | |
success | true | default true |
datarequired | BrowserCheckView | BrowserCheckView fieldsBrowserCheckView, expanded above. |
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. |
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/confirmations/{confirmation_id}Answer the site agent's question (continue or stop)
202: the answer is on the thread and the parked run resumes with it.
Continue lets the agent carry out the plan it described; Stop reverts the work so far. Either way the change goes back to ``planning`` until the agent reports again.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
confirmation_idrequired | path | string | |
authorization | header | string | null |
Request bodyrequired
application/jsonWebsiteModConfirmationBody| Field | Type | Description |
|---|---|---|
decisionrequired | enum | one of "continue", "stop" |
text | string | null | |
client_message_id | string | null | |
attachments | WebsiteAgentAttachmentRef[] | max items 10WebsiteAgentAttachmentRef[] fieldsWebsiteAgentAttachmentRef, expanded above. |
Responses
202Successful Responseapplication/jsonSuccessResponse_WebsiteModChangeResponse_| Field | Type | Description |
|---|---|---|
request_idrequired | string | |
success | true | default true |
datarequired | WebsiteModChangeResponse | WebsiteModChangeResponse fieldsWebsiteModChangeResponse, expanded above. |
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. |
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/merge-conflict/declineDecline rebuilding a change the site's direct edits refused
The owner's "no" to rebuilding a Publish the site's own, direct changes refused: the change is let go for good, and the editor stops calling it a failure (dev 2026-10-02: "no" did nothing, and the question came back).
Nothing is left to clean: the engine retired the change at the refused merge (PR closed, pending cleared, lock released), and this read's own retire catches any leftover. 409 when the thread's failed run noted no such conflict.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Responses
200Successful Responseapplication/jsonSuccessResponse_WebsiteModMergeConflict_| Field | Type | Description |
|---|---|---|
request_idrequired | string | |
success | true | default true |
datarequired | WebsiteModMergeConflict | WebsiteModMergeConflict fieldsWebsiteModMergeConflict, expanded above. |
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. |
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/progress-streamStream website-mod agent progress events (SSE)
Poll Redis progress for the in-flight plan and emit SSE until terminal.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
after_seq | query | integer | default 0 |
authorization | header | string | null |
Responses
200Successful Responsetext/event-streamstring400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/publishPublish the pending website change (approve + merge-deploy)
202: the approval is recorded and the engine merges to main and deploys.
Publish IS the approval — one action, no separate approve step. It is delivered as the control plane's approval decision rather than a direct ``merge_and_deploy`` because the run is parked on that approval signal: a console-side merge would leave the workflow waiting forever on a PR that no longer exists, and the deploy-completion signal it later receives would never be read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Request body
application/jsonWebsiteModPublishBody | null| Field | Type | Description |
|---|---|---|
approval_bundle_ref | string | null | |
comment | string | null |
Responses
202Successful Responseapplication/jsonSuccessResponse_WebsiteModPublishResponse_| Field | Type | Description | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
request_idrequired | string | ||||||||||||||||
success | true | default true | |||||||||||||||
datarequired | WebsiteModPublishResponse | WebsiteModPublishResponse fields
| |||||||||||||||
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. | |||||||||||||||
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/queue/{item_id}Take back a queued request before it goes
Idempotent: a request no longer queued answers ``removed: false``. 409 ``QUEUE_ITEM_SENDING`` for one already on its way.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
item_idrequired | path | string | |
authorization | header | string | null |
Responses
200Successful Responseapplication/jsonSuccessResponse_EditorQueueRemoveResponse_| Field | Type | Description | ||||||
|---|---|---|---|---|---|---|---|---|
request_idrequired | string | |||||||
success | true | default true | ||||||
datarequired | EditorQueueRemoveResponse | EditorQueueRemoveResponse fields
| ||||||
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. | ||||||
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/runsThe website's recent agent runs, each with its progress timeline
What the agent did for each recent request — read back after a page reload so the folded "What the agent did" account stays under the message that asked for it. Two weeks of history, oldest first.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
limit | query | integer | default 10 |
authorization | header | string | null |
Responses
200Successful Responseapplication/jsonSuccessResponse_WebsiteModRunsResponse_| Field | Type | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
request_idrequired | string | ||||||||||
success | true | default true | |||||||||
datarequired | WebsiteModRunsResponse | WebsiteModRunsResponse fields
| |||||||||
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. | |||||||||
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/sessionRead the website's live-preview session (pilot)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Responses
200Successful Responseapplication/jsonSuccessResponse_WebsiteModSessionResponse_| Field | Type | Description | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
request_idrequired | string | |||||||||||||||||||||||||||||||
success | true | default true | ||||||||||||||||||||||||||||||
datarequired | WebsiteModSessionResponse | WebsiteModSessionResponse fields
| ||||||||||||||||||||||||||||||
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. | ||||||||||||||||||||||||||||||
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/session/heartbeatKeep the website's live-preview session leased while the editor is open
The console calls this every minute or so while the site editor is open. A slot whose lease nobody extends lapses (the pool's LEASE_TTL) and the pod goes back to the warm floor — so tabs are viewers, and closing the last one is what frees the slot, never a client-side beforeunload. 404 for a website not in session mode; a website holding no lease gets the plain "enabled, nothing serving" response (pre-warm is what claims).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Responses
200Successful Responseapplication/jsonSuccessResponse_WebsiteModSessionResponse_| Field | Type | Description |
|---|---|---|
request_idrequired | string | |
success | true | default true |
datarequired | WebsiteModSessionResponse | WebsiteModSessionResponse fieldsWebsiteModSessionResponse, expanded above. |
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. |
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/session/prewarmPre-warm the website's live-preview session (pilot)
Called by the console when the operator opens the site editor, so the pod has cloned, installed and booted `next dev` before the first change request arrives — the whole point of pre-warming. Idempotent: a pod already serving this site at the right commit is left alone.
404 for a website not in session mode, so the console can fire this unconditionally and simply learn that the pilot does not apply here.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Responses
200Successful Responseapplication/jsonSuccessResponse_WebsiteModSessionResponse_| Field | Type | Description |
|---|---|---|
request_idrequired | string | |
success | true | default true |
datarequired | WebsiteModSessionResponse | WebsiteModSessionResponse fieldsWebsiteModSessionResponse, expanded above. |
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. |
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/stopStop the change being made, keeping what the site agent has done
The owner's Stop: the site agent's turn ends at its next step, and what it changed so far becomes the change to review — publish it, ask for more, or discard it. (Discard is the stop that throws the work away.) 409 when this thread has no change being made, or its run cannot be reached, or the run the Stop names (``plan_request_id``) is not the one being made: a Stop that arrives late must not stop the queued request that followed.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Request body
application/jsonWebsiteModStopBody | null| Field | Type | Description |
|---|---|---|
plan_request_id | string | null |
Responses
202Successful Responseapplication/jsonSuccessResponse_WebsiteEditorStopResponse_| Field | Type | Description | ||||||
|---|---|---|---|---|---|---|---|---|
request_idrequired | string | |||||||
success | true | default true | ||||||
datarequired | WebsiteEditorStopResponse | WebsiteEditorStopResponse fields
| ||||||
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. | ||||||
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.
/api/v1/admin/businesses/{business_id}/website-mod/undoTake back the newest version of the change in review
The owner's Undo: the change in review goes back to the version before its newest (the branch, the preview, the summary), and the next request builds on that. Only the newest version, while this thread's change waits for review and is not being published; with the version that opened the change left, Discard is the way. What it changed in the business records stays.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
business_idrequired | path | string (uuid) | |
authorization | header | string | null |
Request bodyrequired
application/jsonWebsiteModUndoBody| Field | Type | Description |
|---|---|---|
version_idrequired | string | min length 1 · max length 32 |
Responses
200Successful Responseapplication/jsonSuccessResponse_WebsiteModUndoResponse_| Field | Type | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
request_idrequired | string | |||||||||||||
success | true | default true | ||||||||||||
datarequired | WebsiteModUndoResponse | WebsiteModUndoResponse fields
| ||||||||||||
metadata | ResponseMetadata | null | ResponseMetadata fieldsResponseMetadata, expanded above. | ||||||||||||
meta | ResponseMeta | null | ResponseMeta fieldsResponseMeta, expanded above. |
400Bad request401Unauthorized403Forbidden404Not found422Validation error500Internal server error503Service unavailable
Error bodies: ErrorResponse. See Errors.