Run a web chat
This guide runs a text conversation between a Chat Agent and a person inside your own web page. Your server sends each of the person's messages to Resia and reads the agent's replies back. Resia sends nothing to a phone, so a web chat needs no phone number.
Before you start
- Complete Get access.
- Keep the same Bash terminal open, with
RESIA_API_BASEandRESIA_API_KEYset. - Keep your API key on your server. Never send it to the person's browser.
Create a Chat Agent
Copy this block into your terminal. The agent opens the chat itself, so its instructions say how to start. Write instructions that suit any channel. Do not add STOP, HELP, or other opt-out text. A web chat never needs it, and on SMS Resia adds the notice to the first message.
cat > chat-agent.json <<'JSON'
{
"name": "My first web chat",
"instructions": "You help a patient who is waiting for a prescription refill. Start by asking whether they still need the refill. Answer in short, plain sentences. End the chat when the patient confirms or declines.",
"input_schema": {"type": "object", "properties": {}, "additionalProperties": false},
"analysis_prompt": "Record whether the patient still needs the refill.",
"analysis_schema": {
"type": "object",
"properties": {"needs_refill": {"type": "boolean"}},
"required": ["needs_refill"],
"additionalProperties": false
}
}
JSON
curl --fail-with-body --silent --show-error \
"$RESIA_API_BASE/v1/chat-agents" \
--header "Authorization: Bearer $RESIA_API_KEY" \
--header 'Content-Type: application/json' \
--data-binary @chat-agent.json \
--output chat-agent-response.json
jq '{id, review_status, is_active}' chat-agent-response.json
Expected result: HTTP 201, an id, and the agent's review state.
Continue only when review_status is approved and is_active is true.
API reference: Create a Chat Agent.
Open the chat
Set channel to web. Set participant_handle to your own stable id for the person, such as a user id.
CHAT_AGENT_ID=$(jq -er '.id' chat-agent-response.json)
CHAT_REQUEST_KEY=$(uuidgen)
jq -n --arg agent "$CHAT_AGENT_ID" \
'{chat_agent_id: $agent, channel: "web", participant_handle: "user-42", inputs: {}}' > web-chat.json
curl --fail-with-body --silent --show-error \
"$RESIA_API_BASE/v1/chats" \
--header "Authorization: Bearer $RESIA_API_KEY" \
--header 'Content-Type: application/json' \
--header "Idempotency-Key: $CHAT_REQUEST_KEY" \
--data-binary @web-chat.json \
--output web-chat-response.json
jq '{id, status}' web-chat-response.json
Expected result: HTTP 202 and status pending. The agent now writes its first message.
API reference: Start a chat.
Read the agent's messages
Set the cursor once. AFTER holds the last sequence you have, so each read returns only new messages.
CHAT_ID=$(jq -er '.id' web-chat-response.json)
AFTER=0
Then read the chat's message list about once a second until a new message arrives.
Run this read loop again each time you wait for a reply. It keeps AFTER, so do not run the cursor block again.
for attempt in $(seq 1 30); do
curl --fail-with-body --silent --show-error \
"$RESIA_API_BASE/v1/chats/$CHAT_ID/messages?after=$AFTER" \
--header "Authorization: Bearer $RESIA_API_KEY" \
--output messages.json
if jq -e '.items | length > 0' messages.json > /dev/null; then
jq -r '.items[] | "\(.sequence) \(.role): \(.text)"' messages.json
AFTER=$(jq -er '.items[-1].sequence' messages.json)
break
fi
sleep 1
done
Expected result: within about 30 seconds, message 1 with role agent: the agent's opening message.
chat_status in the response changes from pending to active when the opener is ready.
API reference: Read a web chat's messages.
Send the person's message
Send the person's first message only after the agent's first message is there. Until then the chat is pending and refuses messages.
Send one message at a time: wait for Resia's answer before you send the next message.
Give each message your own client_message_id. Send the same id again after a network error: Resia returns the message it stored the first time and does not reply twice.
MESSAGE_ID=$(uuidgen)
jq -n --arg id "$MESSAGE_ID" '{text: "Yes, I still need it.", client_message_id: $id}' > message.json
curl --fail-with-body --silent --show-error \
"$RESIA_API_BASE/v1/chats/$CHAT_ID/messages" \
--header "Authorization: Bearer $RESIA_API_KEY" \
--header 'Content-Type: application/json' \
--data-binary @message.json \
--output sent.json
jq '{sequence, role}' sent.json
AFTER=$(jq -er '.sequence' sent.json)
Expected result: HTTP 202 with the stored message and its sequence. Run the read loop again, without the cursor block, to get the agent's reply.
API reference: Send a message in a web chat.
End the chat
The agent ends the chat when its task is done, and the list then reports chat_status completed. To end it yourself, cancel it.
curl --fail-with-body --silent --show-error \
--request POST \
"$RESIA_API_BASE/v1/chats/$CHAT_ID/cancel" \
--header "Authorization: Bearer $RESIA_API_KEY" \
--output cancelled.json
jq '{id, status}' cancelled.json
Expected result: HTTP 200. An open chat becomes cancelled. A chat that already ended keeps its status, such as completed when the agent finished it. An ended chat takes no more messages.
API reference: Cancel a chat.
Build it into your page
- Your page sends the person's text to your server. Your server posts it to Resia, then reads the list until a new agent message arrives, and returns that message to the page.
- One person can have one open web chat with each Chat Agent. For parallel sessions, add a session id to
participant_handle. - The full conversation also stays readable through Read one chat.
If something fails
409when you open a chat: this person already has an open web chat with this agent. Read it, or cancel it first.409when you send a message: the agent's first message is not there yet, the chat has ended, or you reused aclient_message_idwith different text.422: the text is empty, only spaces, or longer than 4,000 characters, orclient_message_idis missing.- No agent message after 30 seconds: keep reading, because a reply can take longer when many chats run at once. Do not send the same text again with a new
client_message_id: Resia stores that as a second message, and the agent answers both.

