Get a customer’s reply and recover an interrupted send
Section: DOC-MA-conversations-generation#send-messages-and-get-replies.
Build the part of chat that turns one customer question into a visible answer. Use asynchronous send plus bounded state reads for the main recipe. Retain the accepted run so a disconnect does not cause another copy of the question to run.
Before starting, create a thread and obtain its user-scoped credentials. Replace the example conversation ID with that thread's ID. Keep one unresolved send at a time for the initial integration; the current state response cannot correlate every queued or concurrent operation.
The backend summary and context-only event recipes later in this guide use the same conversation with different completion needs.
Recipe: send a question without holding the request open
Section: DOC-MA-conversations-generation#async-generation.
Use send-message to release the connection after acceptance and retrieve the reply through conversation-state. Validation and context preparation happen before acceptance; the response does not wait for the newly admitted run’s model answer. Keep one unresolved turn for this first flow.
Step 1: Send once and read the same conversation
Section: DOC-MA-conversations-generation#worked-example.
Step 1 — send the message:
curl -X POST https://api.travila.ai/api/v1/llm/send-message \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "b81d5345-c1f9-4fb9-b558-a6327c75b842",
"userMessage": {
"role": "ROLE_USER",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "Hello, what can you help me with?"
}
]
}
}'
Reference: Send a message to a conversation · Request fields.
Response:
{
"runId": "64403669-5989-4ec3-ad9c-d84223f9679f"
}
Reference: Send a message to a conversation · Response fields.
Step 2 — poll conversation-state:
curl -X POST https://api.travila.ai/api/v1/llm/conversation-state \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "b81d5345-c1f9-4fb9-b558-a6327c75b842"
}'
Reference: Get full conversation state · Request fields.
Mid-generation response (while generation is in progress):
{
"messageHistory": [
{
"role": "ROLE_USER",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "Hello, what can you help me with?"
}
],
"timestamp": "2026-04-23T22:43:44.123Z",
"messageId": "2a1f33ce-1abc-4a5d-9e22-1c0d1a2b3c4d",
"sequence": "1"
}
],
"activeRunId": "64403669-5989-4ec3-ad9c-d84223f9679f",
"activeRunning": true
}
Reference: Get full conversation state · Response fields.
Example settled response (timing depends on the model, tools and load):
{
"messageHistory": [
{
"role": "ROLE_USER",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "Hello, what can you help me with?"
}
],
"timestamp": "2026-04-23T22:43:44.123Z",
"messageId": "2a1f33ce-1abc-4a5d-9e22-1c0d1a2b3c4d",
"sequence": "1"
},
{
"role": "ROLE_ASSISTANT",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "I can assist you with..."
}
],
"timestamp": "2026-04-23T22:43:51.653Z",
"messageId": "3f2d44de-8db6-4f67-8e51-5c600902491b",
"sequence": "2",
"generatedBy": "64403669-5989-4ec3-ad9c-d84223f9679f",
"usage": {
"promptTokens": 359,
"completionTokens": 65,
"totalTokens": 424
},
"model": "google/gemini-3.1-flash-lite"
}
],
"lastRunStatus": "AGENT_STATUS_COMPLETED"
}
Reference: Get full conversation state · Response fields.
In this isolated example, activeRunning is absent and the matching assistant message is present. In a busy conversation, lastRunStatus describes the most recent outcome and may refer to another request; history can contain earlier turns.
A lost response does not prove the run failed. Repeating a send can create duplicate work; do not assume an idempotency header makes it safe. Follow retry and reconciliation guidance before repeating a send.
The finished chat turn needs both a reply associated with the retained run and a correlated terminal outcome. The sample is an isolated run; use the steps below when other work or a lost connection makes that correlation uncertain.
Step 2: Finish or recover the accepted turn
Section: DOC-MA-conversations-generation#polling-recipe.
- Call
send-messageonce and retain the conversation and returnedrunId. An accepted or queued response is not a completed reply. - Read
conversation-statewith a bounded polling interval and overall deadline; two seconds between reads and a sixty-second UI deadline are example client choices, not completion SLAs. Honor throttling and back off. - Match assistant messages using
generatedBywhen it identifies the accepted run. UseactiveRunningandactiveRunIdto describe current activity, not to infer the outcome of every prior request. An intermediate tool-round message does not finish the run. - Use
lastRunStatusonly when you can establish that it describes the same run. The current state response does not provide a full per-request outcome lookup for all queued/concurrent cases. If correlation is missing or ambiguous, preserve an unknown/pending outcome and reconcile; do not report success from idle alone. - At your client deadline, stop automatic polling and offer a read/reconnect action. Do not send the mutation again to find out whether it succeeded. For a new single-user flow, avoid concurrent sends while one turn is unresolved.
Finished result: your UI shows the answer for the accepted run, a recognized unsuccessful outcome, or an explicit unresolved state with a reconnect path. It never converts idle activity, an HTTP success response or an intermediate tool message into proof that this question was answered.
Some older threads retain their last activeRunId after the run ends. Test activity through activeRunning, and use the correlated result to decide completion. See the state reference for the complete schema and streaming availability for deployment-specific live updates.
Separate recipe: wait for a backend summary in the response
Section: DOC-MA-conversations-generation#synchronous-generation.
For a backend task that needs a summary before continuing, configure the required object schema with structured output, then use the bounded synchronous request below. The prompt asks for a summary, but asking for JSON is not itself schema configuration.
curl -X POST https://api.travila.ai/api/v1/llm/send-message-sync \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "b81d5345-c1f9-4fb9-b558-a6327c75b842",
"userMessage": {
"role": "ROLE_USER",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "Summarize this thread as JSON."
}
]
}
}'
Reference: Send a message and wait for the result · Request fields.
Response — the generated messages, with token usage, returned directly:
{
"runId": "9d4c...",
"status": "AGENT_STATUS_COMPLETED",
"messages": [
{
"role": "ROLE_ASSISTANT",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "…"
}
],
"generatedBy": "9d4c..."
}
],
"aggregateUsage": {
"promptTokens": 412,
"completionTokens": 88,
"totalTokens": 500
}
}
Reference: Send a message and wait for the result · Response fields.
Accept the result only when the run has finished
Section: DOC-MA-conversations-generation#interpret-the-outcome.
HTTP 200 means the request returned a response, not that generation succeeded.
Use the run-outcome table to interpret status and the messages separately.
For the backend recipe, validate and consume the returned object only after the correct run completes. A queued, active or tool-wait result returns control to your application; retain the operation and continue recovery instead of substituting an empty summary.
Recover a summary that failed or returned no explanation
Section: DOC-MA-conversations-generation#failed-responses-and-diagnostics.
A failed run can return HTTP 200 with a body such as:
{
"runId": "9d4c...",
"status": "AGENT_STATUS_FAILED"
}
Reference: Send a message and wait for the result · Response fields.
Keep the conversation ID and runId for investigation. When an evaluation
backend is provisioned, read traces and observations for separate
diagnostics such as statusMessage; locate the turn using the trace ID or
conversation ID plus source user message ID, as described in
Addressing a turn. Trace content is redacted, and an
unprovisioned evaluation backend returns 424 — see Evals. These APIs
are a separate diagnostic path, not a guarantee of an inline failure explanation.
For JSON/structured replies, set responseFormat in the generation config.
A lost response does not prove the run failed. Repeating a send can create duplicate work; do not assume an idempotency header makes it safe. Follow retry and reconciliation guidance before repeating a send.
Explain why a summary failed
Status: Upcoming — not yet available.
Section: DOC-MA-conversations-generation#inline-failure-details.
When a backend summary fails, the synchronous send and tool-result responses
include an optional inline error from that same run. Use it as the first
explanation, then follow the trace-recovery steps above if it is missing or you
need more context. Details can still be unavailable: keep checking the run’s
status and preserve its ID and any partial reply. A missing explanation does
not turn a failed summary into a successful empty result. The
send reference and
tool-result reference
define the proposed lookup limits.
Separate recipe: record an onboarding event without another reply
Section: DOC-MA-conversations-generation#append-a-message.
When your application confirms onboarding, record that fact for later conversation context without immediately asking the model to speak. Use the example event below only after the application has confirmed it; text in history cannot grant an entitlement.
curl -X POST https://api.travila.ai/api/v1/llm/append-message \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "b81d5345-c1f9-4fb9-b558-a6327c75b842",
"message": {
"role": "ROLE_USER",
"content": [
{
"type": "CONTENT_PART_TYPE_TEXT",
"content": "CONTEXT UPDATE: user completed onboarding."
}
]
}
}'
Reference: Append a message without generating · Request fields.
Finished result: the event is present in thread history and no generation was started by this append. The next ordinary message can use stored history according to its context settings; the append does not change a provider request already in flight.
Document ID: DOC-MA-conversations-generation. Section identities and revisions.