Skip to main content
POST
JavaScript
An objective that answers you does not end. It parks in STATE_WAITING with its context window open, holding everything it learned. Continue it and the agent picks up mid-thought, with every tool result and memory read from the previous turns still in front of it. That is the difference between a conversation and a series of unrelated requests.
The call returns the userMessage event it appended, not the agent’s reply. The objective drops back to STATE_PENDING and starts working. Read the answer by streaming events or waiting for STATE_WAITING again.
In bash and zsh, brace the variable: "${OBJECTIVE_ID}:continue". Unbraced, the shell eats the :c as a modifier and the request lands on a path that does not exist.

Only a waiting objective accepts a turn

This is the whole contract, and it is strict: A message is required. An empty body is a 400. So a chat UI where the user types while the agent is still answering has to wait. There is no fire-and-forget: you poll or stream until the objective is waiting, then send.
Streaming is the better shape for a real UI: watch for the assistant’s last message, enable your input box, and send when the user submits. Polling like the preceding code is the version that fits in a page.
The request carries an enqueue flag, described as buffering the message until the agent loop is free. It has no effect today. A STATE_RUNNING objective rejects the call with or without it.

What carries across a turn

Everything. That is the point. The context window persists, so previous tool results, memory reads, and assistant reasoning stay available. Compaction handles the window filling up: old turns get summarized or their tool bodies stripped, and the objective keeps going rather than failing. What you cannot change mid-conversation: the variation, the system prompt, the assigned tools, or the memory cascade. All of that was snapshotted into configSnapshot when the objective was created. A turn is a message, not a reconfiguration. Publish a new variation and existing conversations keep running the old one, which is usually what you want.

Driving a conversation

The full loop, with the first turn and every turn after it looking almost the same:
Set metadata.externalId on the objective and your session ID becomes the handle. A web server handling turn seventeen needs nothing in its database beyond the session. To end a conversation, cancel it. A waiting objective holds its context window until something closes it, and an idle objective is eventually finalized as STATE_TIMED_OUT by the variation’s inactivityTimeout, or by the system-wide 24-hour sweep.

Create an objective

The first turn, and where the conversation’s configuration is fixed.

Stream objective events

Watch the reply arrive instead of polling for it.

Compaction

What happens to a long conversation when the window fills.

Use your own IDs

Address a conversation by your session ID, forever.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Path Parameters

workspaceId
string
required
Example:

"workspace_01HXKD2E5NQM3T9AYWCF133E3Q"

objectiveId
string
required

The ID of the objective. If you have assigned an external ID to the objective, you can prefix the ID with "external_id:". For example, "external_id:1234567890". Otherwise, the ID assigned by Cadenya should be used.

Example:

"obj_01HXKD2E5NQM3T9AYWCFQAZGFV"

Body

application/json
message
string
required

The message to continue an objective that has completed (or you are enqueing)

enqueue
boolean

When set to true, the message will be enqueued for when the agent loop is available to process it.

Response

OK

metadata
object
required

Metadata for ephemeral operations and activities (e.g., objectives, executions, runs)

data
object
required
contextWindowId
string
Example:

"objwin_01HXKD2E5NQM3T9AYWCFN7BSTR"

info
object
duration
string
read-only

Elapsed time of the work this event records, when it is known at write time (e.g. assistant message generation, tool execution for result/error events). Unset means the event is instantaneous or the duration is not measurable. Serialized as a canonical duration string (e.g. "4.1s"). Always set together with started_at.

Pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$
startedAt
string<date-time>
read-only

When the work this event records began. Set together with duration, so the work interval is [started_at, started_at + duration]. The event's created_at remains the time the event was persisted.