How to Talk to a Vibe Site's AI Agent
Drive a Vibe site's conversational AI agent over HTTP to build and update a site.
You can drive a Vibe site's AI agent over HTTP using the Partner API Conversations endpoints. This agent is the same agent that powers the Vibe editor chat, without requiring the editor interface. You can open a conversation, send instructions, inspect the actions the agent took, and answer interactive questions.
The agent operates in build mode. It does not support plan mode. Communication follows a post-and-poll workflow. Each turn takes tens of seconds to several minutes, and the agent does not stream output.
Prerequisites
Before you start, ensure that you have:
- Partner API credentials for HTTP Basic authentication.
- A target site created with the Vibe editor (
editor: "VIBE"). If you target any other site type, the API returns anInvalidStateerror with the message "This site type has no conversational agent".
Workflow overview
The conversation workflow uses the following sequence:
- Create a conversation for the Vibe site.
- Post an instruction or attachment to start a turn.
- Poll the conversation state until the turn finishes or asks for input.
- Read the conversation log to review messages and actions.
- Answer any interaction requests if the agent pauses for a decision.
A site can run only one turn at a time. If you send another post while a turn is in progress, the API rejects the request.
1. Create a conversation
To create a new conversation, send a POST request to the conversations endpoint. Creating a conversation costs nothing and runs no tasks.
curl -X POST "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations" \
-H "Authorization: Basic $AUTH"The API returns the conversation object:
{
"id": "f8b89941-8447-4d42-901f-02ad1a0f367a",
"state": "idle",
"created_at": "2026-09-14T08:05:51.212Z",
"last_activity_at": "2026-09-14T08:05:51.212Z"
}The response omits the title field initially. The agent names the conversation at the end of its first turn.
A conversation persists until the site is deleted. The API does not provide endpoints to rename or delete conversations.
List conversations
To list all conversations for a site, send a GET request:
curl "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations" \
-H "Authorization: Basic $AUTH"The endpoint returns a JSON array ordered by last_activity_at with the most recent activity first:
[
{
"id": "f8b89941-8447-4d42-901f-02ad1a0f367a",
"state": "idle",
"title": "Bookings page",
"created_at": "2026-09-14T08:05:51.212Z",
"last_activity_at": "2026-09-14T08:06:48.590Z"
}
]The response contains a bare JSON array without pagination or wrapper objects.
2. Post an instruction to start a turn
To start a turn, send a POST request to the items endpoint with your instruction.
The content array accepts at most one text part, plus any number of file parts.
curl -X POST "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations/$CONVERSATION_ID/items" \
-H "Authorization: Basic $AUTH" \
-H "Content-Type: application/json" \
-d '{
"content": [
{
"type": "text",
"text": "Add a bookings page that stores reservations"
}
]
}'The endpoint returns HTTP 202 Accepted:
{
"state": "in_progress"
}The turn runs in the background after the response returns.
Attach files
To attach a file, add an object with type: "file" to the content array. The file URL must use the HTTP or HTTPS protocol and must be publicly reachable. The agent fetches the URL directly:
{
"content": [
{
"type": "text",
"text": "Use this logo in the header"
},
{
"type": "file",
"url": "https://cdn.example.com/logo.png"
}
]
}3. Poll conversation state
To check whether the agent finished working, send a GET request to the conversation endpoint:
curl "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations/$CONVERSATION_ID" \
-H "Authorization: Basic $AUTH"Check the state field in the response:
| State | Description | Action to take |
|---|---|---|
in_progress | A turn is running. | Wait a few seconds and poll again. Do not post new messages. |
idle | Nothing is running. | The turn finished. Post your next message or read the log. |
waiting_for_answer | The agent paused and needs a decision. | Read the log for the open request, then post an answer. |
4. Read the conversation log
To inspect messages, files, and agent actions, send a GET request to the items endpoint:
curl "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations/$CONVERSATION_ID/items?limit=50" \
-H "Authorization: Basic $AUTH"The log returns items in chronological order, oldest first:
{
"results": [
{
"id": "MTc4OTM3MzE4NDEwNCN4NEo0eHI",
"type": "message",
"created_at": "2026-09-14T08:06:24.104Z",
"role": "user",
"text": "Add a bookings page that stores reservations"
},
{
"id": "MTc4OTM3MzIwODU5MCN2VFpvYTM",
"type": "message",
"created_at": "2026-09-14T08:06:48.590Z",
"role": "assistant",
"text": "Got it — building your bookings page now."
}
],
"limit": 50,
"next_cursor": "MTc4OTM3MzM1MDY2OCN6aXp0Q2E",
"state": "idle"
}Log pagination
To fetch subsequent pages, pass the next_cursor value into the cursor query parameter:
curl "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations/$CONVERSATION_ID/items?limit=50&cursor=MTc4OTM3MzM1MDY2OCN6aXp0Q2E" \
-H "Authorization: Basic $AUTH"The limit parameter bounds the number of stored database rows read, not the number of items returned. One stored row can produce multiple items, and some rows produce no items. As a result, a page can contain more or fewer items than the limit value. Follow next_cursor until it is absent or null. Do not infer the end of the log from the count of items.
Item types
Every log item includes id, type, and created_at.
| Type | Author | Contents |
|---|---|---|
message | User (role: "user") or agent (role: "assistant") | text |
file | User | name, url |
interaction_request | Agent | request_id, kind, prompt, payload, answered_by |
answer | User or agent | request_id, answer |
Clients must ignore unrecognized item types and unexpected fields. The platform adds new types over time.
5. Answer an interaction request
When the conversation state switches to waiting_for_answer, the agent has stopped to request a decision.
The log includes an interaction_request item. The kind property indicates what the agent requires:
| Kind | Description | Expected answer |
|---|---|---|
approval | A decision on a schema change or site plan. | approved boolean |
credential | Permission to use environment variables. | approved boolean |
question | One or more choices presented by the agent. | answers array |
The payload field contains internal agent structures forwarded without modification. Treat the payload as display data.
Approve a request
Here is an example of an approval interaction request:
{
"id": "MTc4OTM3MzM0Mzc2MiNKQW5ZYlE",
"type": "interaction_request",
"created_at": "2026-09-14T08:09:03.762Z",
"request_id": "2e7da21a-2809-4005-81b8-2662a27dea64",
"kind": "approval",
"payload": {
"changes": [
{
"action": "createTable",
"tableName": "customers",
"columns": [
{
"name": "name",
"type": "string",
"references": null
},
{
"name": "email",
"type": "string",
"references": null
}
]
}
]
}
}To approve or reject the request, send a POST request with an answer content part:
curl -X POST "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations/$CONVERSATION_ID/items" \
-H "Authorization: Basic $AUTH" \
-H "Content-Type: application/json" \
-d '{
"content": [
{
"type": "answer",
"request_id": "2e7da21a-2809-4005-81b8-2662a27dea64",
"approved": true
}
]
}'After the decision is recorded, the interaction request item displays the answered_by field. The log also receives a corresponding answer item:
{
"type": "answer",
"id": "MTc4OTM3NTczMDg3OCNiMjJWRlI",
"created_at": "2026-09-14T08:48:50.878Z",
"request_id": "2e7da21a-2809-4005-81b8-2662a27dea64",
"answer": {
"kind": "schemaRequest",
"approved": true
}
}Answer question cards
A single question card can present multiple questions. Answer all questions on the card in a single POST request.
In each entry in the answers array, pass question_id exactly as given in payload.questions[].id. The ID can contain colons.
Set exactly one of four fields per answer entry:
| Field | Usage |
|---|---|
selected_label | A single choice when multiple is false. Must match an option label string exactly. |
selected_labels | An array of choice label strings when multiple is true. |
other_text | Free-form text when none of the provided choices fit. |
skipped | Set to true to decline the choice. This is recorded as an explicit decision. |
The following example answers a three-question card in one request:
curl -X POST "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations/$CONVERSATION_ID/items" \
-H "Authorization: Basic $AUTH" \
-H "Content-Type: application/json" \
-d '{
"content": [
{
"type": "answer",
"request_id": "83f98fd2-2ad7-4a41-b2e2-50941c1db062",
"answers": [
{
"question_id": "tooluse_DIoLsYCLTXpF2bmQEOdsQd:0",
"selected_labels": [
"Hero",
"Features / Benefits",
"Contact form"
]
},
{
"question_id": "tooluse_DIoLsYCLTXpF2bmQEOdsQd:1",
"selected_label": "Cool & professional"
},
{
"question_id": "tooluse_DIoLsYCLTXpF2bmQEOdsQd:2",
"other_text": "store them in a table called leads"
}
]
}
]
}'If you post a plain text message while an interaction request is open, the agent starts a new turn. The open request remains unanswered permanently.
Cancel a running turn
To abort a turn in progress, send a POST request to the cancel endpoint:
curl -X POST "https://api.duda.co/api/sites/multiscreen/$SITE_NAME/conversations/$CONVERSATION_ID/cancel" \
-H "Authorization: Basic $AUTH"The endpoint returns HTTP 204 with an empty body.
Cancellation is eventual. The running turn stops at its next internal checkpoint.
If you call cancel when nothing is running, the API returns 204 without error.
Handle errors
Client-facing errors return HTTP 400 with a typed JSON body:
{
"error_code": "InvalidInput",
"message": "unknown type 'video'; expected one of [answer, file, text]"
}Inspect error_code rather than the HTTP status code. Common error codes include:
| Error code | Cause |
|---|---|
InvalidInput | The request body contains an invalid content part, such as an unknown type, a missing or non-HTTP file URL, multiple text parts, or invalid answer combinations. |
InvalidState | A post was submitted while a turn was already running, an answer was sent for an already settled request, or the site is not a Vibe site. |
ResourceNotExist | The conversation, item, or request ID does not exist. |
Authentication failures return HTTP 401 when API credentials are missing or invalid.
The API does not forward internal agent error text. If the agent rejects a request, the API returns the message "The agent rejected the request".
Updated 12 days ago