Skip to content

Quickstart: Hello ticket

This page gets you from an API key to an agent’s reply in four HTTP calls, written for developers who usually work with REST. The example domain is a support ticket, but nothing here is ticket-specific: the same four calls run any agent.

There is one URL, and every call is an HTTP POST to it with a JSON body { "query": "...", "variables": { ... } }. Each operation (for example sdkStart) plays the role of an endpoint, and the query lists the fields you want back, so the response holds exactly those. Errors come back in a JSON errors array, each with a machine-readable extensions.code (see Errors); most of them arrive with HTTP status 200, so always check errors before reading data. Every request also carries the header x-huat-platform: customer.

  • An API key (sk_...) from the sandbox. A workspace member creates one with createNamedApiKey; keep it on your server only.
  • The id of an agent with a published workflow in that workspace (WETEL_AGENT_ID). Building agents and workflows is covered in Agents and the workflow overview.
StepOperationCredentialWhat comes back
1sdkStartAPI key (X-Api-Key)sessionId and a session token (avatarToken)
2sdkSendMessagesession token (Authorization: Bearer <avatarToken>)true: an acknowledgement, not the reply
3sessionsByExternalCustomerIdAPI keythe session’s messages; repeat until a reply shows
4sdkEndSessionsession tokenthe session’s duration

The reply is generated asynchronously (the agent may call tools first), so step 3 polls: every two seconds, for at most sixty, it reads the session’s messages and stops when a MODEL message follows your USER message.

Each tab is a complete program. Set WETEL_API_KEY and WETEL_AGENT_ID and run it; the comment at the top of each file has the exact command. The same files are on Downloads.

hello-ticket.sh
#!/usr/bin/env bash
# Hello ticket: start a session, send one message, poll for the reply, end the session.
# Needs curl and jq. Run: WETEL_API_KEY=sk_... WETEL_AGENT_ID=7 bash hello-ticket.sh
set -euo pipefail
API_URL="${WETEL_API_URL:-https://api.wetel.dev/graphql}"
AGENT_ID="${WETEL_AGENT_ID:-1}"
CLIENT_ID="ticket-$(date +%s)" # one clientId per conversation
TEXT="My laptop cannot connect to the office VPN since this morning."
read -r -d '' START <<'GRAPHQL' || true
mutation StartSession($input: SdkStartInput!) {
sdkStart(input: $input) {
sessionId
avatarToken
agentId
graphqlEndpoint
}
}
GRAPHQL
read -r -d '' SEND <<'GRAPHQL' || true
mutation SendMessage($input: SdkSendMessageInput!) {
sdkSendMessage(input: $input)
}
GRAPHQL
read -r -d '' POLL <<'GRAPHQL' || true
query PollSession($externalCustomerId: String!, $first: Int) {
sessionsByExternalCustomerId(externalCustomerId: $externalCustomerId, first: $first) {
totalCount
edges {
node {
id
status
messages {
id
role
text
turnIndex
createdAt
}
}
}
}
}
GRAPHQL
read -r -d '' END <<'GRAPHQL' || true
mutation EndSession($input: SdkEndSessionInput!) {
sdkEndSession(input: $input) {
sessionId
durationSeconds
evaluation {
score
summary
}
}
}
GRAPHQL
# gql QUERY VARIABLES_JSON AUTH_HEADER: prints .data, or the first error and exits.
gql() {
local response
response=$(jq -n --arg query "$1" --argjson variables "$2" '{query: $query, variables: $variables}' |
curl -sS "$API_URL" -H "Content-Type: application/json" -H "x-huat-platform: customer" -H "$3" --data-binary @-)
if [ "$(jq '.errors | length' <<<"$response")" != "0" ]; then
jq -r '.errors[0] | "\(.extensions.code): \(.message)"' <<<"$response" >&2
exit 1
fi
jq '.data' <<<"$response"
}
# 1. Start a session with the API key.
STARTED=$(gql "$START" "$(jq -n --argjson agentId "$AGENT_ID" --arg clientId "$CLIENT_ID" '{input: {agentId: $agentId, clientId: $clientId}}')" "X-Api-Key: $WETEL_API_KEY")
SESSION_ID=$(jq '.sdkStart.sessionId' <<<"$STARTED")
AVATAR_TOKEN=$(jq -r '.sdkStart.avatarToken' <<<"$STARTED")
# 2. Send the message with the session token. It returns true at once.
gql "$SEND" "$(jq -n --argjson sessionId "$SESSION_ID" --arg text "$TEXT" '{input: {sessionId: $sessionId, text: $text}}')" "Authorization: Bearer $AVATAR_TOKEN" >/dev/null
# 3. Poll the session's messages until the reply arrives
# (the reply is every MODEL message after the last USER message).
REPLY=""
DEADLINE=$(($(date +%s) + 60))
while [ -z "$REPLY" ] && [ "$(date +%s)" -lt "$DEADLINE" ]; do
sleep 2
POLLED=$(gql "$POLL" "$(jq -n --arg clientId "$CLIENT_ID" '{externalCustomerId: $clientId, first: 1}')" "X-Api-Key: $WETEL_API_KEY")
REPLY=$(jq -r --argjson id "$SESSION_ID" '
.sessionsByExternalCustomerId.edges[].node | select(.id == $id) | .messages
| ((map(.role) | rindex("USER")) // -1) as $u
| .[($u + 1):] | map(select(.role == "MODEL") | .text) | join("\n")' <<<"$POLLED")
done
echo "${REPLY:-No reply within the timeout.}"
# 4. End the session with the session token.
gql "$END" "$(jq -n --argjson sessionId "$SESSION_ID" '{input: {sessionId: $sessionId}}')" "Authorization: Bearer $AVATAR_TOKEN" >/dev/null
  • One clientId per conversation. Step 3 finds the session through the clientId you passed to sdkStart, which is why the program builds a fresh one (ticket-<timestamp>). Use your own ticket or conversation id in a real integration.
  • Do not poll faster than once a second. A reply usually takes a few seconds and can take longer when the workflow calls tools. Keep a timeout and end the session either way.
  • Only messages after yours count. The program reads the messages that follow your last USER message, so anything earlier in the session (an earlier turn, a greeting) is never mistaken for the reply.
  • With a dashboard JWT you can read one session directly with session(id) { messages }. That operation does not accept an API key.
  • Browsers receive replies as they stream over the sessionEvents subscription instead of polling: see Core API Flow and Events and Subscriptions.
  • The session token lasts about an hour. Renew it on the same session with refreshAvatarToken.