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_BASE and RESIA_API_KEY set.
  • 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

  • 409 when you open a chat: this person already has an open web chat with this agent. Read it, or cancel it first.
  • 409 when you send a message: the agent's first message is not there yet, the chat has ended, or you reused a client_message_id with different text.
  • 422: the text is empty, only spaces, or longer than 4,000 characters, or client_message_id is 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.