Skip to main content

End user sessions

Use end user sessions to let the people using your product talk to an agent directly from their own browser or mobile app. The end user's own credential creates, runs, and reads their own conversations, so your backend does not have to proxy every message, and the platform enforces that no end user can ever see another end user's sessions.

End users always reach an agent through an alias, never through an agent key. The alias is the public name you hand to your client; behind it you can re-route, split, or replace agents without changing anything the client calls.

Two ways to expose a session​

Vectara agents expose sessions through two different surfaces, for two different callers.

Operator sessions (/v2/agents/{agent_key}/sessions)End user sessions (/v2/agent_aliases/{alias_key}/end_user_sessions)
CallerYour backend, holding an API keyThe person chatting with the agent
VisibilityEvery event, including tool traces and reasoningThe session's messages, the client tool calls it waits on, and the output types its widget connector reveals
OwnershipCan act across any of your customer's sessionsLocked to the caller's own identity
CredentialAPI key or application clientA platform user holding agent_end_user, an anonymous widget visitor (an X-Visitor-Id minted through POST /v2/visitors), or a federated end user (a token from your own identity provider)

If your backend already mediates every message (for example, to inject session metadata for per-user access control), operator sessions are still the right surface. Reach for end user sessions when you want to hand the session credential directly to an untrusted client, such as a browser tab or a mobile app, and skip building your own proxy.

What end user sessions guarantee​

A caller can only ever reach their own sessions​

There is no parameter anywhere in this API for choosing whose sessions to read. The owning principal is stamped from the caller's authenticated identity when the session is created, and it can't be set or changed afterward. Listing sessions returns only the caller's own, and getting, sending to, or deleting a session owned by someone else returns 403, never that other person's data.

This isolates your end users from each other, not from you. An end user session is a regular agent session underneath, so it still appears in your own session list and in the Console, where your team can read it, inspect its full event history, and delete it. Plan for that when deciding what your end users are invited to type into a conversation.

End users see messages, and only what you reveal​

The full agent event stream includes internal detail — reasoning traces, tool calls, step transitions, compaction — that isn't meant for an end user. End user sessions always expose these event types:

  • input_message — what the end user said.
  • agent_output — what the agent replied.
  • error — a turn-ending failure signal, carrying a generic message that does not identify the underlying cause. Without it, a failed turn would be indistinguishable from one that simply produced no reply.
  • client_tool_pending — the client tool calls the agent waits on the end user to answer. See Answer client tool calls.
  • tool_input and tool_output of client tools — each client tool call and the output the end user submitted for it.

A widget connector can also reveal the calls of every other tool, reasoning, and structured output through its revealed_output_types. Every other event type is invisible to an end user. New event types are invisible by construction, so an agent that starts using one cannot start leaking it.

Grant a user access​

An end user is any principal holding the agent_end_user role, scoped to one specific alias key. This role grants nothing else. A user account is the usual holder, but an API key, an application client, an anonymous widget visitor, or a federated end user may hold it too: each owns the sessions it creates and reaches no one else's. The other agent roles reach these operations as well, and an agent administrator is bound to its own sessions the same way; the operator endpoints under /v2/agents/{agent_key}/sessions remain the administrative view of an alias's sessions.

The role must name an alias. Granting it on an agent key is rejected — publish the agent behind an alias and grant on that alias key instead.

The role grants the end-user session operations of the alias it names and nothing else — not reading users, not creating API keys, not querying corpora. That is what makes the credential safe to hand to an untrusted client: adding agent_end_user to an account never widens what that account can reach.

You can hold it alongside other roles, which is useful for testing your own published agent from a developer account. Bear in mind that such an account still has everything its other roles grant, so for a credential you intend to ship to a browser or mobile app, give the end user their own account rather than adding the role to a teammate's existing one.

Grant access (Console)​

  1. Log into the Vectara Console.
  2. Navigate to the Team page.
  3. Select the user you want to grant access to.
  4. Open the Agents access tab.
  5. Click Grant access to agent, choose the alias, select Agent end user, and click Grant access.

Grant access (API)​

Send a PATCH request to the user's endpoint with the role scoped to your alias's key.

Grant the agent_end_user role

Code example with multiple language options.
1

See Update user for the full request shape. The agent_key field carries the alias key here; agent keys and alias keys are separate namespaces for a customer.

Create a session and chat​

Once a user holds the role, they authenticate as themselves and call the dedicated end user endpoints with their own credential.

Create a session

Code example with multiple language options.
1

Every end user session binds to the widget connector named by the required connector_id, which is what carries its settings (its idle lifetime, the event types it reveals, and the session_metadata written under metadata.connector.<connector_id> of each of its sessions, which the agent reads as session.metadata.connector.*). The named connector must be an enabled widget connector created on the addressed alias, or the request is rejected with 400. name and description are optional; if you omit them, the server names the session for you and fills in a description once the agent has produced a response.

The alias resolves which agent handles the session once, at creation time. If you later shift the alias's routing, sessions created before the shift keep running on the agent they started with, and your client keeps calling the same alias URL throughout.

Send a message

Code example with multiple language options.
1

The response contains that turn's visible events. Sending a message while the session is already processing one returns 409. To attach files to a message, send the same request as multipart form data with one or more files parts.

Stream the response​

Set stream_response to true on the same request to receive the reply as Server-Sent Events. Live text arrives incrementally as streaming_agent_output chunks, followed by the complete, persisted agent_output event.

Streaming response

Code example with bash syntax.
1

Answer client tool calls​

A client tool (type: client) is a tool that the client runs instead of the platform. When the agent calls one in an end user session, the response ends with a client_tool_pending event, and the session waits until the end user's client submits the call's output. Use client tools to show the end user something the agent produces, such as a form, and to bring back what the end user enters.

Each entry in pending_calls carries the event_id of the call, the tool_name, and the arguments to run the tool with. The arguments include any values that the tool configuration's argument overrides resolve, with secret values unmasked. In a widget session the client is the visitor's browser, so do not override a client tool's arguments with a secret or any other value that the end user must not see.

The client_tool_pending event is not saved with the session's history. A client that reconnects or reloads reads the calls the session is waiting on from GET /v2/agent_aliases/{alias_key}/end_user_sessions/{session_key}/outstanding_client_tool_calls.

The history keeps each client tool call as a tool_input event and the submitted output as a tool_output event with the same tool_call_id, so a client can show the forms an end user already answered. These events carry the arguments the agent wrote, without the values of the tool configuration's argument overrides.

To answer, submit a tool_output input with one entry for each pending call. An entry is either a success with the tool's output, or an error that tells the agent why the call failed. When the client tool defines an output_schema, an output that does not match it is rejected with 400.

Submit a client tool output

Code example with json syntax.
1

The agent then continues the turn with the output, and the response contains the turn's visible events. A client that cannot run a tool should answer with an error entry, because the session cannot continue until every pending call has an output.

Limits​

Each end-user principal has a per-customer cap on live sessions and on sessions created per hour. Exceeding either returns 429. Delete a session to free up capacity within the live-session cap; the hourly cap resets on a rolling basis.

A session's idle lifetime is not something the end user sets. It comes from the widget connector the session binds to: the widget's session_tti_minutes is applied to every session created through its alias, and the session is deleted automatically after that long without activity. The effective value is reported back as tti_minutes on the session object.

Restricting widget origins​

Set configuration.allowed_origins on a widget connector to restrict browser access:

JSON
{
"configuration": {
"type": "widget",
"allowed_origins": ["https://example.com", "https://*.example.com"]
}
}

Use up to 20 unique lowercase HTTPS origins, each at most 255 characters, without ports, paths, or trailing slashes. Wildcards match subdomains at any depth, excluding the apex and origins with ports.

On create, omitted or [] allows any origin. On update, omitted preserves the list; null or [] clears it. Null entries are rejected.

With a non-empty list, unmatched Origin headers receive 403 on the public connector view and session creation, reads, deletion, events, and inputs. This applies to anonymous and signed-in callers. Visitor minting and session listing are exempt.

Existing sessions pick up changes within a few seconds. Disabling or deleting the connector stops origin checks; other admission and ownership checks still apply.

Requests without Origin are allowed, so this setting does not restrict non-browser clients.

Next steps​