Keystone Developers
Open Keystone
API reference

Console API

Website modifications

16 endpoints.

GET/api/v1/admin/businesses/{business_id}/website-mod

Read 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_WebsiteModStateResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModStateResponse
WebsiteModStateResponse fields
FieldTypeDescription
thread_idrequiredstring
website_idrequiredstring
thread_statusstring | null
thread_failure_codestring | null
thread_failure_messagestring | null
merge_conflictWebsiteModMergeConflict | null
WebsiteModMergeConflict fields
FieldTypeDescription
summaryrequiredstring
changestringdefault ""
rebuild_requeststringdefault ""
declinedbooleandefault false
messagesobject[]default []
object[] fields
pending_changeWebsiteModPendingChange | null
WebsiteModPendingChange fields
FieldTypeDescription
website_idrequiredstring
business_idrequiredstring
thread_idrequiredstring
workflow_run_idrequiredstring
summaryrequiredstring
approval_staterequiredstring
registered_atnumber | null
confirmationobject | null
agent_model_idstring | null
approval_statestring | null
approval_bundle_refstring | null
workflow_run_idstring | null
preview_urlstring | null
preview_head_shastring | null
preview_frame_shastring | null
preview_kindstring | null
session_enabledbooleandefault false
publishablebooleandefault false
progressWebsiteModProgress | null
WebsiteModProgress fields
FieldTypeDescription
stagestring | null
eventsWebsiteModProgressEvent[]default []
WebsiteModProgressEvent[] fields

Nested object (not expanded)

plan_request_idstring | null
headlinestring | null
pending_confirmationWebsiteModConfirmation | null
WebsiteModConfirmation fields
FieldTypeDescription
confirmation_idrequiredstring
questionrequiredstring
why_criticalstringdefault ""
planstringdefault ""
impactstringdefault ""
asked_atnumber | null
data_changed_atnumber | null
pending_data_changesstring[]default []
string[] fields
capabilitiesEditorCapabilities
EditorCapabilities fields
FieldTypeDescription
model_pickerbooleandefault false
default_model_idstring | null
attachmentsEditorAttachmentsCapability
EditorAttachmentsCapability fields

EditorAttachmentsCapability (not expanded)

stopbooleandefault false
undobooleandefault false
steeringbooleandefault false
browser_checkbooleandefault false
billingbooleandefault false
queuebooleandefault false
browser_checkBrowserCheckView | null
BrowserCheckView fields
FieldTypeDescription
idrequiredstring
statusrequiredstring
blockedrequiredboolean
problemsstring[]
string[] fields

Nested object (not expanded)

pagesBrowserCheckPage[]
BrowserCheckPage[] fields

Nested object (not expanded)

checked_atstring (date-time) | null
overriddenbooleandefault false
override_reasonstring | null
can_recheckbooleandefault false
recheckingbooleandefault false
versionsWebsiteModVersion[]default []
WebsiteModVersion[] fields

WebsiteModVersion (not expanded)

undone_versionsWebsiteModVersion[]default []
WebsiteModVersion[] fields

WebsiteModVersion (not expanded)

queued_requestsEditorQueuedRequest[]default []
EditorQueuedRequest[] fields

EditorQueuedRequest (not expanded)

queueEditorQueueState | null
EditorQueueState fields
FieldTypeDescription
statusenumone of "waiting", "sending", "held", "blocked", "idle" · default "waiting"
reasonstring | null
messagestring | null
batchEditorQueueBatch | null
EditorQueueBatch fields

EditorQueueBatch (not expanded)

deliveredEditorQueueDelivered | null
EditorQueueDelivered fields

EditorQueueDelivered (not expanded)

metadataResponseMetadata | null
ResponseMetadata fields
FieldTypeDescription
paginationPaginationMetadata | null
PaginationMetadata fields
FieldTypeDescription
limitrequiredinteger
next_cursorstring | null
prev_cursorstring | null
has_morerequiredboolean
has_prevbooleandefault false
total_countinteger | null
status_countsobject | null
object | null fields

Map of string to integer

lifecycle_countsLifecycleCounts | null
LifecycleCounts fields
FieldTypeDescription
leadintegerdefault 0
prospectintegerdefault 0
customerintegerdefault 0
former_customerintegerdefault 0
classification_countsClassificationCounts | null
ClassificationCounts fields
FieldTypeDescription
signalobject
object fields

Nested object (not expanded)

touchobject
object fields

Nested object (not expanded)

stageobject
object fields

Nested object (not expanded)

metaResponseMeta | null
ResponseMeta fields
FieldTypeDescription
totalinteger | null
total_countinteger | null
pageinteger | null
per_pageinteger | null
  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/cancel

Cancel 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Request body

application/jsonWebsiteModCancelBody | null
FieldTypeDescription
commentstring | null

Responses

200Successful Response
application/jsonSuccessResponse_WebsiteModCancelResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModCancelResponse
WebsiteModCancelResponse fields
FieldTypeDescription
cancelledrequiredboolean
thread_idrequiredstring
cleared_pendingrequiredboolean
released_lockrequiredboolean
closed_pull_request_numbersinteger[]default []
integer[] fields
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/changes

Submit 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Request bodyrequired

application/jsonWebsiteModChangeBody
FieldTypeDescription
textrequiredstring | null
client_message_idstring | null
model_idstring | null
attachmentsWebsiteAgentAttachmentRef[]max items 10
WebsiteAgentAttachmentRef[] fields
FieldTypeDescription
kindrequiredenumone of "photo", "document"
idrequiredstringmin length 1 · max length 64 · pattern ^[A-Za-z0-9-]+$
deliveryenum | null

Responses

202Successful Response
application/jsonSuccessResponse_WebsiteModChangeResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModChangeResponse
WebsiteModChangeResponse fields
FieldTypeDescription
thread_idrequiredstring
workflow_run_idstring | null
statusrequiredstring
steeredbooleandefault false
queuedbooleandefault false
queued_request_idstring | null
note_refusedbooleandefault false
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/check/override

Let 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Request bodyrequired

application/jsonBrowserCheckOverrideBody
FieldTypeDescription
reasonrequiredstringmin length 10 · max length 1000

Responses

200Successful Response
application/jsonSuccessResponse_BrowserCheckView_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredBrowserCheckView
BrowserCheckView fields

BrowserCheckView, expanded above.

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/check/recheck

Look 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Responses

202Successful Response
application/jsonSuccessResponse_BrowserCheckView_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredBrowserCheckView
BrowserCheckView fields

BrowserCheckView, expanded above.

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/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

NameInTypeDescription
business_idrequiredpathstring (uuid)
confirmation_idrequiredpathstring
authorizationheaderstring | null

Request bodyrequired

application/jsonWebsiteModConfirmationBody
FieldTypeDescription
decisionrequiredenumone of "continue", "stop"
textstring | null
client_message_idstring | null
attachmentsWebsiteAgentAttachmentRef[]max items 10
WebsiteAgentAttachmentRef[] fields

WebsiteAgentAttachmentRef, expanded above.

Responses

202Successful Response
application/jsonSuccessResponse_WebsiteModChangeResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModChangeResponse
WebsiteModChangeResponse fields

WebsiteModChangeResponse, expanded above.

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/merge-conflict/decline

Decline 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_WebsiteModMergeConflict_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModMergeConflict
WebsiteModMergeConflict fields

WebsiteModMergeConflict, expanded above.

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

GET/api/v1/admin/businesses/{business_id}/website-mod/progress-stream

Stream website-mod agent progress events (SSE)

Poll Redis progress for the in-flight plan and emit SSE until terminal.

Parameters

NameInTypeDescription
business_idrequiredpathstring (uuid)
after_seqqueryintegerdefault 0
authorizationheaderstring | null

Responses

200Successful Response
text/event-streamstring
  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/publish

Publish 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Request body

application/jsonWebsiteModPublishBody | null
FieldTypeDescription
approval_bundle_refstring | null
commentstring | null

Responses

202Successful Response
application/jsonSuccessResponse_WebsiteModPublishResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModPublishResponse
WebsiteModPublishResponse fields
FieldTypeDescription
publishedrequiredboolean
thread_idrequiredstring
workflow_run_idrequiredstring
approval_bundle_refrequiredstring
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

DELETE/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

NameInTypeDescription
business_idrequiredpathstring (uuid)
item_idrequiredpathstring
authorizationheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_EditorQueueRemoveResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredEditorQueueRemoveResponse
EditorQueueRemoveResponse fields
FieldTypeDescription
removedrequiredboolean
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

GET/api/v1/admin/businesses/{business_id}/website-mod/runs

The 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
limitqueryintegerdefault 10
authorizationheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_WebsiteModRunsResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModRunsResponse
WebsiteModRunsResponse fields
FieldTypeDescription
website_idrequiredstring
runsWebsiteModRun[]default []
WebsiteModRun[] fields

WebsiteModRun (not expanded)

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

GET/api/v1/admin/businesses/{business_id}/website-mod/session

Read the website's live-preview session (pilot)

Parameters

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_WebsiteModSessionResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModSessionResponse
WebsiteModSessionResponse fields
FieldTypeDescription
website_idrequiredstring
enabledrequiredboolean
statusstring | null
repostring | null
base_shastring | null
preview_urlstring | null
timings_sobjectdefault {}
object fields

Map of string to number

slotstring | null
expires_atnumber | null
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/session/heartbeat

Keep 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_WebsiteModSessionResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModSessionResponse
WebsiteModSessionResponse fields

WebsiteModSessionResponse, expanded above.

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/session/prewarm

Pre-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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_WebsiteModSessionResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModSessionResponse
WebsiteModSessionResponse fields

WebsiteModSessionResponse, expanded above.

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/stop

Stop 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Request body

application/jsonWebsiteModStopBody | null
FieldTypeDescription
plan_request_idstring | null

Responses

202Successful Response
application/jsonSuccessResponse_WebsiteEditorStopResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteEditorStopResponse
WebsiteEditorStopResponse fields
FieldTypeDescription
stoppingrequiredboolean
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/admin/businesses/{business_id}/website-mod/undo

Take 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

NameInTypeDescription
business_idrequiredpathstring (uuid)
authorizationheaderstring | null

Request bodyrequired

application/jsonWebsiteModUndoBody
FieldTypeDescription
version_idrequiredstringmin length 1 · max length 32

Responses

200Successful Response
application/jsonSuccessResponse_WebsiteModUndoResponse_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredWebsiteModUndoResponse
WebsiteModUndoResponse fields
FieldTypeDescription
undonerequiredboolean
newest_version_idrequiredstring
summarystringdefault ""
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.