Skip to main content
Semi can propose writes while it helps you buy or run a storefront: creating or launching a campaign, changing a storefront’s setup, filing an ask for the Semicola team. For protected writes Semi doesn’t run the write straight away. It returns a structured pending confirmation, and the write runs only after a person approves it. A client renders each pending confirmation as an explicit Approve / Cancel control. The control exists only when the response carries a structured pending confirmation; text in Semi’s answer can never create one.

When a plain “yes” is enough

In the Semicola app you can approve by pressing Approve, or by replying in chat. A short, plain reply such as “yes”, “ok”, “sounds good” or “go ahead” approves the open confirmations only when every one of them has plainAffirmativeAccepted: true. Otherwise Semi asks you to use the button.
  • Some tools always need the button or the launch phrase, save_campaign among them, so their confirmations have plainAffirmativeAccepted: false.
  • Spend and launch never accept a plain “yes”. Press Approve, or type the exact phrase confirm launch.
  • Tainted confirmations (policy: "tainted") need the button. A turn becomes tainted once Semi has read content it didn’t write, such as an uploaded file or text from a seller. Text from those sources can contain instructions, and your click is what stops such an instruction from acting in your name.
  • Anything that isn’t a clear, short approval, including a conditional or mixed reply, approves nothing.

Confirmation lifecycle

  1. Send a chat turn with POST /api/v2/assistant/chat or POST /api/v2/assistant/chat/stream.
  2. If the response has entries in pendingConfirmations, show each proposed action with its own approve/cancel control. A single turn can propose several writes; each entry has its own confirmationUid and is decided independently.
  3. Post each decision to POST /api/v2/assistant/confirmations/{confirmationUid}/decision.
  4. On confirm, the write runs and Semi finishes the turn it paused. The response carries the resumed chat response.
  5. On cancel, nothing runs and the response only records the cancelled status.
A confirmationUid is short-lived and single-use. It expires 15 minutes after it’s issued and is bound to the tool and the exact parameters shown. Don’t store it as a lasting approval.

Pending confirmation fields

The chat response (and the confirmation frame of the stream) carries pendingConfirmations, an array in tool-call order. It’s empty when nothing needed approval.

Confirm or cancel

The response is { confirmationUid, status, response? }. status is confirmed, cancelled or expired. After a confirm that finishes the paused turn, response holds the same shape as a chat response, and the write that ran appears in toolsUsed. Send Accept: text/event-stream to receive the resumed turn as stream frames instead.

Errors

  • 400 VALIDATION_ERROR: the body is malformed.
  • 404 NOT_FOUND: the confirmation is unknown, or belongs to a chat you can’t see.
  • 409 CONFLICT: a response is still running in this chat. Wait for it to finish, then decide.
  • An expired confirmation returns status: "expired" and nothing runs. Ask Semi again for a fresh one.

Confirmations over MCP

Agents that call the v3 MCP endpoint get the same gate as a tool result: status: "pending_confirmation" with a confirmationUid. After the person approves, call the same tool again with the same arguments plus confirm: true and the confirmationUid. Changed arguments are refused. See Errors for the result shape.

Errors

pending_confirmation, needs_input and the error codes.

Limits

Confirmation expiry and other limits.