- Flows are intent-level only. An agent operates flow agents but never sees or edits how they are built.
- Campaigns are draft-only. An agent can prepare a blast but never send one.
Why these boundaries exist
Intent, not implementation
Agents describe what a flow should do; Sapot Chat decides how to build it. The Designer graph is product IP and stays server-side.
A human confirms every send
A blast reaches real customers. An agent assembles it and reports the reach; a person reviews and clicks Send.
Flows are intent-level only
An agent operates flow agents by intent — it can list them, inspect their name, status, connected inboxes, and runtime metrics, attach inboxes, and publish. It never receives the underlying flow graph. What is stripped from every agent-token response. The Flow Designer’sgraph_data, graph_snapshots, and designer_history are removed server-side before any agent-reachable render returns. The tools reflect this — list_flow_agents and get_flow_agent return the intent-level view (id, name, description, status, conversational_mode, reply_delay_seconds, handoff_pause_duration, inbox_ids, inbox_settings) and nothing more.
There is no build tool. There is no create-from-scratch, export, import, or restore-snapshot tool in the catalog. Graphs are authored and fixed in the Sapot Chat Flow Designer in the dashboard.
Publish returns an opaque error. publish_flow_agent validates the graph first; if it is invalid, the call fails — but the error an agent receives is deliberately opaque. Detailed validator strings embed node labels, node types, and branch names (product IP), so those stay on the dashboard only.
What to do at this boundary: operate what you can (set_flow_agent_inboxes, then publish_flow_agent), and when a graph needs to change, hand it to a human in the Flow Designer. See Flow Agents for the operate-and-publish recipe.
Campaigns are draft-only
An agent can read campaigns, preview an audience, and draft or edit a draft. It can never fire the blast. A drafted campaign is forced non-sending. A campaign created or edited through an agent token is forced tocampaign_status: "draft" (and enabled: false) server-side — merged last, so it always wins no matter what an agent sends. The scheduler only ever fires scheduled campaigns, and the trigger path early-returns on a draft, so a draft cannot slip into the send queue.
An agent can only edit its own drafts. update_campaign_draft edits a draft and leaves it a draft. Editing a campaign that is not a draft is refused with a 403 — an agent can neither send a campaign nor pull a live one back out of the queue.
There is no send scope. The only campaign scope is campaigns:draft. No scope, and no tool, sends a campaign. Sending happens exactly one way: a human opens Campaigns in the dashboard and clicks Send, which promotes the draft to scheduled.
What to do at this boundary: run preview_campaign_audience to report the reach, draft_campaign to prepare the blast, then tell the user: “Draft ready — open Campaigns and click Send to blast to N contacts.” See Campaigns for the full draft-then-hand-off recipe.
Treat a boundary as expected, not a failure
Both boundaries surface as ordinary tool responses, and neither is worth retrying or working around:These are product boundaries, distinct from scope denials (a capability your key wasn’t granted) and quota limits (
429). See Authentication & Scopes for those.Related
Flow Agents
Operate and publish flow agents at the intent level.
Campaigns
Draft a blast, preview the audience, and hand off to a human to send.

