Skip to main content
POST
Refine a composed agent
Change the agent a composer session is holding, by saying what you want changed.
Like designing one, this answers 202 straight away and applies the change in the background:
Poll GET /agents/composer/{sessionId} for the updated preview, or send a webhookId when you start the session and be told instead.
Still no agent. Refining changes the preview the session is holding. Nothing exists in your account until you post to POST /agents.

One turn at a time

A session applies one instruction at a time. Send another while one is still running and you get a 409 immediately, without spending anything — wait for the session to leave processing and send it again. The session keeps showing the previous agent throughout. A refinement in flight does not take away the preview you already had: you can still read it, and still create it.

You do not send the agent back

The session holds the agent, so a follow-up carries only your instruction. There is nothing to keep in sync on your side, and no way to accidentally send back a stale version of the conversation. You can refine as many times as you like within the session’s 30 days.

What a message can do

Anything the visual builder can do to a custom agent — the composer and the in-app copilot are the same thing behind different doors:
Renaming is only ever on request. If you pinned a name when you started the session, it stays pinned — the composer will not quietly relabel your agent while doing something else.

A rejected change leaves the agent alone

Every turn is validated the same way the create route validates a flow. If a change would break the conversation — emptying a required message, leaving a conditional with one branch — the session comes back failed with the reason, and the agent is untouched: no half-applied edit, and the preview you had before is still there to read, to create, or to try a different instruction against. A rejected change is not free, though: the instruction reached the model before it was found to be unapplicable, so it counts against your rate limit like any other turn. Only a 409 — refused before any work started — costs nothing.
This is also what keeps the promise that the preview is postable: the agent a session hands you has passed the create route’s checks at every step, not just at the start.

Errors

These are the ways the request can fail. A change that fails after it has been accepted is not an error here — it is a failed session, described above.
An unknown session, an expired one, and one belonging to another company are all a 404. They are deliberately indistinguishable.
Ask for one thing at a time. A single instruction is applied faster than a compound one, and is much easier to review afterwards.

Authorizations

Authorization
string
header
required

API key for authentication using Bearer scheme

Path Parameters

sessionId
string<uuid>
required

The composer session id returned by POST /agents/composer.

Query Parameters

companyId
string

Required for ATS API keys to specify which company to access. Ignored for standard company API keys.

Body

application/json
message
string
required

What to change, in plain language.

Maximum string length: 4000
Example:

"Also ask about relocation, and make the whole call Slovak."

Response

The turn was accepted and is running. Poll GET /agents/composer/{sessionId} for the result.

sessionId
string<uuid>
required

The session to poll, to send follow-up messages to, and to create the agent from.

status
enum<string>
required

Always processing here: the turn has been accepted and is running.

Available options:
processing
expiresAt
string<date-time>
required

When this session is deleted if you never create the agent. Sessions live 30 days.