Run a text-message chat

This guide covers a text conversation that a person starts: they text your Resia number, and a Chat Agent answers. You do not send POST /v1/chats for this chat. Resia starts it when the first text arrives.

Before you start

  • Complete Get access.
  • Keep the same Bash terminal open, with RESIA_API_BASE and RESIA_API_KEY set.
  • Use a Resia number that your organization owns. The agent's replies need that number on an active 10DLC campaign; see Register for 10DLC texting. The assignment below is refused until the number shows as ASSIGNED on that campaign; see See which numbers are on a campaign.

Create a Chat Agent for texts to your number

The person's text opens the chat, so the agent answers it. For a first test, use an agent that needs no inputs. Do not add STOP, HELP, or other opt-out text. On SMS, Resia adds that notice itself.

cat > inbound-chat-agent.json <<'JSON'
{
  "name": "My first inbound text agent",
  "instructions": "You answer questions from patients who text the clinic. Answer in short, plain sentences. End the chat when the patient has no more questions.",
  "input_schema": {"type": "object", "properties": {}, "additionalProperties": false},
  "analysis_prompt": "Record the patient's main question.",
  "analysis_schema": {
    "type": "object",
    "properties": {"question": {"type": "string"}},
    "required": ["question"],
    "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 @inbound-chat-agent.json \
  --output inbound-chat-agent-response.json

jq '{id, review_status, is_active}' inbound-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.

Assign the agent to your number

This action changes which Chat Agent answers new texts to the selected number. A number can have an inbound Call Agent and an inbound Chat Agent at the same time. This request changes only the Chat Agent.

read -r -p 'Your Resia number, including + and country code: ' RESIA_PHONE_NUMBER
CHAT_AGENT_ID=$(jq -er '.id' inbound-chat-agent-response.json)

jq -n --arg agent "$CHAT_AGENT_ID" \
  '{inbound_chat_agent_id: $agent}' > inbound-chat-assignment.json

curl --fail-with-body --silent --show-error \
  --request PATCH "$RESIA_API_BASE/v1/phone-numbers/$RESIA_PHONE_NUMBER" \
  --header "Authorization: Bearer $RESIA_API_KEY" \
  --header 'Content-Type: application/json' \
  --data-binary @inbound-chat-assignment.json

Expected result: HTTP 200 with the selected inbound_chat_agent_id. If the number is not ASSIGNED on an active 10DLC campaign, the response is 422, because the agent's replies would fail at the carrier. Attach the number with Put a number on a campaign, wait until it shows as ASSIGNED, and retry. If the agent needs inputs and has no inbound_input_webhook_url, the response is 422, because a text that starts a chat has no inputs of its own. Add the webhook below, or assign an agent that needs no inputs.

API reference: Assign an inbound agent.

Test it

  1. Text the Resia number from another phone.
  2. List the agent's chats and find the new one.
  3. Read that chat to see the transcript.
curl --fail-with-body --silent --show-error \
  "$RESIA_API_BASE/v1/chats?chat_agent_id=$CHAT_AGENT_ID&limit=5" \
  --header "Authorization: Bearer $RESIA_API_KEY" \
  --output inbound-chats.json

jq '.items[] | {id, status, participant_handle}' inbound-chats.json

Expected result: A new chat with status active and your phone number as participant_handle. Later texts from the same person go to the same chat until it ends. To stop answering texts on the number, send {"inbound_chat_agent_id": null} through the same PATCH operation.

API reference: List chats and Read one chat.

Choose who can text: the inbound webhook

Without a webhook, anyone who texts the number starts a chat. To give the agent information about the person, or to answer only people you know, set inbound_input_webhook_url on the Chat Agent with Replace a Chat Agent.

When a text starts a new chat, Resia sends this to your HTTPS URL before the agent answers:

{
  "type": "chat.incoming",
  "chat": {
    "channel": "sms",
    "participant_handle": "+12125550142",
    "agent_handle": "+16465550175"
  }
}

It never contains the text. Later texts in the same chat do not send it.

Reply within 30 seconds with HTTP 200 and this envelope, where inputs matches the agent's input_schema:

{"inputs": {}}

An agent that declares patient_name receives {"inputs": {"patient_name": "Ada"}}, and its instructions can use $patient_name.

Any other answer starts no chat, and Resia sends no reply: another status such as 404, no answer within 30 seconds, an unreadable body, or inputs that do not match. So the webhook is an allow list. Answer 200 for a person you know and 404 for anyone else. Your webhook must tolerate duplicate requests without side effects.

This differs from a call. When an inbound call's webhook fails, a Call Agent that needs no inputs still answers.

API reference: The chat.incoming event.

If something fails

  • 422 when you assign the agent and the message names 10DLC: the number is not ASSIGNED on an active campaign yet. See which numbers are on a campaign.
  • 422 when you assign the agent: the agent needs inputs and has no inbound_input_webhook_url.
  • No chat after a text: check the number assignment and that the agent is active. If a webhook is set, inspect request logs for its response or timeout.
  • A chat, but no reply reaches the phone: check that the number is on an active 10DLC campaign.