Public Assistants

This guide explains how to expose EpsimoAI assistants for public access — without requiring callers to have an EpsimoAI user account or JWT. This is essential for embedding assistants in external platforms (Typebot, Zapier, custom websites) or building public-facing chatbots.


Overview

Every assistant has an access mode that controls who can call it via the public endpoints. There are three modes:

Access Mode Auth Required Use Case
authenticated Yes (JWT) Default. Only logged-in EpsimoAI users via /runs/stream
public_token Yes (per-assistant token) External integrations, embedded bots
public_no_auth No Public demos, VPN-protected internal tools

Access Mode: authenticated (Default)

This is the default for all assistants. The assistant can only be used through the authenticated /runs/stream endpoint with a valid user JWT.

Public endpoints will reject requests with:

{
  "detail": "This assistant is not configured for public access. Please use the authenticated /runs endpoints instead, or set type==agent/access_mode to 'public_token' or 'public_no_auth'."
}

Configuration

No action needed — this is the default. To explicitly set it:

curl -X PATCH https://backend.epsimoagents.com/assistants/<assistant-id> \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "configurable": {
        "type==agent/access_mode": "authenticated"
      }
    }
  }'

Security Implications


Access Mode: public_token

The assistant is accessible via public endpoints to anyone who presents the correct token. The token acts as a per-assistant API key.

Configuration

Set two config values on the assistant:

curl -X PATCH https://backend.epsimoagents.com/assistants/<assistant-id> \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "configurable": {
        "type==agent/access_mode": "public_token",
        "type==agent/public_token": "pubkey_mybot_abc123"
      }
    }
  }'

Token recommendations: - Use a prefix like pubkey_ for easy identification - Generate a random suffix: pubkey_$(openssl rand -hex 16) - Store it securely — anyone with this token can use your assistant (and your LLM credits)

How to Pass the Token

The token can be provided in three ways (checked in this order):

  1. Authorization: Bearer <token> header — compatible with OpenAI SDKs and Typebot
  2. X-Public-Bot-Token: <token> header — EpsimoAI-specific header
  3. token field in the JSON body — for the /public/runs/stream endpoint

Security Implications


Access Mode: public_no_auth

The assistant is fully open — no token or authentication of any kind is required.

Configuration

curl -X PATCH https://backend.epsimoagents.com/assistants/<assistant-id> \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "configurable": {
        "type==agent/access_mode": "public_no_auth"
      }
    }
  }'

Security Implications


Public Endpoints

/public/runs/stream — Native Streaming Endpoint

The EpsimoAI-native endpoint for public assistant interaction. Returns Server-Sent Events (SSE).

Request Format

curl -N https://backend.epsimoagents.com/public/runs/stream \
  -H "X-Public-Bot-Token: pubkey_mybot_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "assistant_id": "<assistant-id>",
    "thread_id": "session-12345",
    "input": [{"role": "human", "content": "Hello!"}]
  }'

Request Body Fields

Field Type Required Description
assistant_id string Yes The assistant's UUID
thread_id string Yes A stable session identifier. Maintains conversation state.
input array or object No Messages to send. Array of message objects or a state dict.
config object No Optional per-call configuration overrides
token string No Alternative to the X-Public-Bot-Token header

Input Formats

Array of messages (most common):

{
  "input": [
    {"role": "human", "content": "What's the weather like?"}
  ]
}

State dictionary:

{
  "input": {
    "messages": [
      {"role": "human", "content": "What's the weather like?"}
    ]
  }
}

Response Format (SSE)

The response is a stream of Server-Sent Events:

event: metadata
data: {"run_id": "..."}

event: messages/partial
data: [{"type": "ai", "content": "Hello! "}]

event: messages/partial
data: [{"type": "ai", "content": "Hello! How can I help?"}]

event: end
data: {}

Each messages/partial event contains the full accumulated message content up to that point (not just the delta).


/public/openai/v1/chat/completions — OpenAI-Compatible Endpoint

Mimics the OpenAI API format. See the full OpenAI-Compatible Endpoint guide for details.

curl https://backend.epsimoagents.com/public/openai/v1/chat/completions \
  -H "Authorization: Bearer pubkey_mybot_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello!"}],
    "stream": false
  }'

Key difference from /public/runs/stream: the token alone identifies the assistant (no assistant_id field needed).


The X-Public-Bot-Token Header

EpsimoAI's custom header for passing the public access token. An alternative to Authorization: Bearer.

When to use it: - When calling /public/runs/stream directly - When the Authorization header is already used for something else - When you prefer explicit separation from JWT-based auth

curl -N https://backend.epsimoagents.com/public/runs/stream \
  -H "X-Public-Bot-Token: pubkey_mybot_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "assistant_id": "abc-123-def",
    "thread_id": "my-session",
    "input": [{"role": "human", "content": "Hi"}]
  }'

Thread/Session Management

For public assistants, the thread_id in the request body serves as the session identifier:

The thread is created automatically on first use — no separate "create thread" call is needed for public endpoints.

Best practices: - Use your platform's session ID as the thread_id (e.g., Typebot's sessionId) - For anonymous web widgets, generate a UUID per browser session and store it in localStorage - Thread IDs are strings — any format works (UUIDs, slugs, hashes)


Comparison of Public Endpoints

Feature /public/runs/stream /public/openai/v1/chat/completions
Format EpsimoAI native (SSE) OpenAI-compatible JSON/SSE
Assistant identification assistant_id in body Token lookup (no ID needed)
Token header X-Public-Bot-Token Authorization: Bearer
Thread management Explicit thread_id Managed internally per token
Streaming Always SSE Optional (stream: true/false)
Best for Custom integrations OpenAI SDK, Typebot, no-code tools

Security Best Practices

  1. Prefer public_token over public_no_auth unless you have network-level controls.
  2. Rotate tokens regularly — especially if you suspect a leak.
  3. Monitor usage — watch your LLM provider's billing dashboard for unexpected spikes.
  4. Use descriptive token prefixes — makes it easy to identify which assistant a leaked token belongs to.
  5. Set up billing alerts on your LLM provider (OpenAI, Anthropic, etc.) as a safety net.
  6. Consider a reverse proxy with rate limiting (e.g., AWS WAF, Cloudflare) in front of public endpoints for production deployments.