FruxonDocs
ApiFruxon channel

Injects a turn into the session as the chosen participant.

The run is queued; the reply arrives on the stream / messages endpoints. The participant must already be bound to the session's agent — an unbound sender is dropped and filed as an access request. On a sandbox session the participant is optional. Omitted, the turn speaks as the session's recorded participant, or else as the caller's own test customer: an external contact with no real channel, created and bound to the agent on first use. A non-draft turn on an agent that has never been deployed is a 400, since there is no published version to run. A session that records its participant — a fork's customer, a widget's visitor, or the test customer once an unnamed turn has run — speaks as that one only. Naming anyone else is a 409: the turn would start a second, empty conversation inside this one. The operator of a takeover rehearsed on the session is the exception, since that turn is relayed to the customer. `revisionPolicy: PROPOSAL` with a `recommendationId` runs that card's change, made to the deployed release in memory — what approving the card would deploy — without saving anything. Agent admins only (403); 409 when the card has no change waiting or the live agent already has it. 503 means the turn was <b>deferred</b>, not lost: participant resolution faulted, so admission could not be decided and nothing was enqueued. On a provider webhook this asks for a redelivery; here the caller is the widget, so it must be told to retry rather than sit waiting on a stream that will never produce a reply.

POST
/v1/tenants/{tenant}/fruxon/sessions/{session}/turns
AuthorizationBearer <token>

JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token.

In: header

Path Parameters

session*string

The session id returned by open.

tenant*string

The tenant identifier

The participant to speak as and the turn text.

participantId?string|null

The participant to speak as. Optional on a sandbox session: omitted, the turn speaks as the session's recorded participant (a fork's subject), or else as the caller's own test customer — an external contact with no real channel, created and bound to the agent on first use.

Formatuuid
text?string
asyncExecutionMode?string

Optional per-turn async-execution-mode override (sandbox debug console). Forces this run's async tools (consult / approval / delegate) to await or background, winning over each step's deployed AsyncExecution.Mode for this turn only — so an operator can exercise the suspend-and-answer loop without redeploying the agent. Omitted (or UNSPECIFIED) = no override: the deployed step config applies (current behavior). Honoured only for sandbox sessions; nothing is persisted to the agent.

Value in"UNSPECIFIED" | "AGENT_DECIDES" | "FORCE_AWAIT" | "FORCE_BACKGROUND"
revisionPolicy?string

Which body of the agent's code this turn runs: the deployed release (default, unchanged behaviour), the caller's own draft, or a recommendation card's change (FruxonRevisionPolicy.Proposal, with SendFruxonTurnRequest.RecommendationId). FruxonRevisionPolicy.Draft is what closes the edit-then-test loop — without it, seeing whether a fix works means publishing it to every real customer first — and PROPOSAL does the same for a change a review proposed. 400 when the caller has no draft for the agent, and sandbox sessions only. See FruxonChannel.FruxonRevisionPolicy.

Value in"UNSPECIFIED" | "PUBLISHED" | "DRAFT" | "PROPOSAL"
confirmToolCalls?boolean|null

Hold every tool call that changes something until the operator confirms it, for this turn. Sandbox sessions only.

The sandbox hard-blocks channel sends and memory writes, and simulates every connection with no sandbox saved unless SendFruxonTurnRequest.SandboxRouting chooses Live for it. What can still change something real is a connection chosen Live, and a built-in that acts on the workspace itself. This is the guard for those. Only a call that reaches production is held: not a read — a confirmation queue nobody reads is worse than none — and not a write the run sends to the simulator or a vendor sandbox. Each held call suspends the run on the ordinary human-approval gate and surfaces on the console's existing approval card, naming the arguments and why the call reaches production.

sandboxRouting?|null

How to route a connection the agent uses on this run, by connection id: SIMULATED, READ_THROUGH, or NONE — shown as Live, which reaches the connection with its production credentials. Sandbox sessions only (a Live session is refused). A connection left out is simulated unless it has a sandbox saved: a sandbox session never reaches production through an integration unless you choose Live for it. Nothing is saved on the connection.

replyStyle?

The reply style to run this turn with instead of the agent's active one: {"version": 3} for a particular version (a draft under review, say), or {"off": true} for none — send the same message both ways to compare. Sandbox sessions only (a Live session is refused): a real conversation always gets the reply style an admin activated. A version the agent does not have runs with none.

previewReplies?boolean|null

Stream the reply as it is written, as PARTIAL frames on the session stream, instead of only the whole REPLY at the end. Sandbox sessions only — a Live session already streams, since a web caller has no other transport back.

Off by default. A conversation turn against a real agent runs for tens of seconds, and a reader watching a spinner for that long cannot tell a working run from a wedged one. The cost of asking is that partials are drafts: the run can still end silent, parked or failed, so a client that opts in must take the text back when no REPLY follows the terminal frame. Frames are bus-only and never persisted; the reply row remains the transcript.

baseRevision?integer|null

With revisionPolicy: DRAFT, run the caller's draft of this published revision rather than whichever draft the session would pick. The studio sends the revision it is open on; 0 is the draft of an agent that has never been deployed. 400 when the caller has no draft of it, and when sent without DRAFT.

Formatint64
draftVersion?integer|null

With revisionPolicy: DRAFT, the draft version the caller last saw. 409 when the draft has moved on since, so a test never runs a head its author has not seen. Omit to run the draft as it stands (the console, which has no editor state to assert). 400 when sent without DRAFT.

Formatint64
recommendationId?string|null

With revisionPolicy: PROPOSAL, the recommendation card whose change this run makes to the deployed release, in memory — what approving the card would deploy. Required with PROPOSAL, 400 without it. Agent admins only (403); 409 when the card has no change waiting, or the live agent already has it; 400 when the change cannot be made yet, with the reason.

Formatuuid
attachments?|null

Files this message carries, as references to storage the caller has already uploaded to (POST storage) — the same upload the studio's single-run path makes.

They land on InboundMessage.Attachments, where a real customer's photo or PDF lands, so the run sees what it would see in production: a screenshot with no caption stays an unstated request, and the tools that read a file get one to read. Without this a turn could only ever carry words, and anything the agent does because of an attachment was untestable.

[key: string]?never

Response Body

curl -X POST "https://api.fruxon.com/v1/tenants/string/fruxon/sessions/string/turns" \  -H "Content-Type: application/json" \  -d '{}'
Empty
{
  "type": "string",
  "title": "string",
  "status": 0,
  "detail": "string",
  "instance": "string",
  "property1": null,
  "property2": null
}
Empty
{
  "type": "string",
  "title": "string",
  "status": 0,
  "detail": "string",
  "instance": "string",
  "property1": null,
  "property2": null
}
{
  "type": "string",
  "title": "string",
  "status": 0,
  "detail": "string",
  "instance": "string",
  "property1": null,
  "property2": null
}
{
  "type": "string",
  "title": "string",
  "status": 0,
  "detail": "string",
  "instance": "string",
  "property1": null,
  "property2": null
}
Empty