REDA One Help Center
EN
Language
English EN Español ES Português PT Italiano coming soon Français FR Deutsch coming soon العربية coming soon
reda.one ↗
Home / REDA AI / Administration / External Widget API Reference

External Widget API Reference

Public REST Contract Four POST endpoints power every external chatbot conversation. Most customers use the shipped widget loader, which calls these endpoints for you. This page documents the contract for teams building their own widget, integrating the chat into a mobile app, or driving the API from another system.

Base URL

The widget API is served from your Salesforce Site, under the path /services/apexrest/redaai/chat/v1/:

https://<your-org>.my.salesforce-sites.com/chat/services/apexrest/redaai/chat/v1/

The exact host depends on your Site domain. Get it from Setup › Sites; the loader script you embed on your website uses the same path under the data-endpoint attribute.

Authentication

Every request requires an API key. Pass it either as an HTTP header or in the request body — the API checks both:

Where Name
HTTP header X-REDAAI-API-Key
Body field clientKey

Salesforce Sites can strip custom headers in some configurations, which is why the body fallback exists. Use either; the body form is more reliable across CDNs and proxies, and is what the shipped widget loader uses by default.

After /init, every subsequent request also needs the session token returned by /init:

Where Name
HTTP header X-REDAAI-Session
Body field sessionToken

See API Key Management for generating, rotating and revoking keys.

CORS

The API echoes Access-Control-Allow-Origin for browser callers. The agent definition can restrict callers via the Allowed Origins field (comma-separated origin list); leave it blank to allow any origin. When set, only the listed origins succeed; others receive an ORIGIN_NOT_ALLOWED error.

Changed in V1.13. The origin is taken from the request’s Origin header, not from the request body. A request with no Origin header — any server-to-server call — is therefore rejected when Allowed Origins is set. See POST /chat/v1/init.

Endpoints

Five endpoints, all POST. Pre-flight OPTIONS requests are handled automatically.

Path Purpose
POST /chat/v1/initStart a new chat session and return a session token.
POST /chat/v1/messageSend a user message and receive the agent’s reply.
POST /chat/v1/actionExecute a confirmed action that the agent proposed.
POST /chat/v1/historyFetch the messages for the active session’s conversation.
POST /chat/v1/continueAsk the agent to narrate the outcome of actions it auto-executed on the previous turn. No new user message is sent.

POST /chat/v1/init

Validates the API key, checks the caller’s origin, and creates a session. Returns the session token plus the agent metadata your widget needs to render the welcome state.

Request body

{
  "clientKey": "<your api key>"
}

Changed in V1.13. The caller’s origin is now taken from the request’s Origin header — set by the browser and not overridable by page scripts. An origin field in the request body is still accepted for backward compatibility but is ignored: a value supplied by the caller cannot be used to restrict the caller. Widgets that still send it keep working unchanged.

This matters for non-browser callers. A server-to-server request carries no Origin header, so it is rejected with ORIGIN_NOT_ALLOWED when the agent has Allowed Origins set. If you call this API from your own backend, leave Allowed Origins blank and restrict access another way. See Configuring Allowed Origins.

Response (200 OK)

{
  "sessionToken":     "<opaque session token>",
  "agentName":        "support-assistant",
  "displayName":      "Support Assistant",
  "welcomeMessage":   "Hi! How can I help today?",
  "mascotImage":      "https://…/mascot.png",
  "maxMessageLength": 2000
}
  • sessionToken — pass on every subsequent request.
  • agentName — the agent’s identifier, useful for analytics on the client side.
  • displayName — the human-readable name to show in the widget header and welcome hero.
  • welcomeMessage — the agent’s configured external welcome text. Empty string when not configured.
  • mascotImage — the mascot URL when one is configured. Empty string when not.
  • maxMessageLength — the length cap for user messages, in characters.

POST /chat/v1/message

Sends a single user message to the agent. Returns the agent’s reply once the agentic loop completes.

Request body

{
  "clientKey":    "<your api key>",
  "sessionToken": "<from /init>",
  "message":      "What's open on the Acme account?"
}

Messages exceeding maxMessageLength (returned by /init) are rejected with INVALID_INPUT.

Response (200 OK)

{
  "response":            "<agent reply text>",
  "creditsUsed":         1.42,
  "conversationId":      "a0Q…",
  "pendingActions":      [],
  "continuationPending": true,
  "continuationDepth":   0
}
  • response — the agent’s reply, including any embedded SUGGESTIONS or ACTION markers the widget renderer parses.
  • creditsUsed — credits consumed by this turn.
  • conversationId — the Salesforce ID of the conversation record. Useful for cross-referencing with the Conversation transcript in Salesforce.
  • pendingActions — actions awaiting client confirmation. On the External Widget channel this is always empty, because confirmation cards exist only on the Internal channel. See POST /chat/v1/action below.
  • continuationPending — true when the agent executed one or more actions this turn and has not yet narrated the outcome. Call /chat/v1/continue to get that narration.
  • continuationDepth — how many continuation turns have already run. Pass it back on the next /continue call.

POST /chat/v1/action

Executes a named Action tool on demand. Only Action tools assigned to the agent and scoped to the External Widget channel are accepted.

The External Widget channel does not use confirmation cards. Those exist only on the Internal channel. When a widget agent decides to take an action, REDA AI executes it immediately, captures the real outcome, and flags continuationPending so the agent can narrate what it did on the next /continue call. Nothing waits for a click.

So this endpoint is not the second half of a confirmation handshake — it is here for widgets that drive their own action UI (your own buttons, your own confirmation step) and want to trigger a specific tool themselves.

Assign Action tools to a public widget agent deliberately. Any Action tool the agent can reach will run without a human gate. Give a customer-facing agent only the tools you are content to have executed on a visitor’s say-so.

Request body

{
  "clientKey":    "<your api key>",
  "sessionToken": "<from /init>",
  "actionTool":   "create_record",
  "params": {
    "object_name":  "Case",
    "field_values": { "Subject": "Issue with login", "…": "…" }
  }
}

Response (200 OK)

{
  "success": true,
  "result":  "<tool execution result, JSON-serialised>"
}

The shape of result matches the underlying tool’s result. For built-in action tools, that means a structured payload with at least a success flag, a message, and (when applicable) a recordId.

POST /chat/v1/continue

Asks the agent to narrate the outcome of actions it executed on the previous /message turn. No new user message is sent. Call it whenever a response comes back with continuationPending: true.

Request body

{
  "clientKey":         "<your api key>",
  "sessionToken":      "<from /init>",
  "continuationDepth": 0
}

Response (200 OK)

{
  "response":            "<agent narration of what happened>",
  "creditsUsed":         0.68,
  "conversationId":      "a0Q…",
  "continuationPending": false,
  "continuationDepth":   1
}

continuationPending stays true if the agent chained another action while narrating, so treat this as a loop: keep calling /continue, passing back the returned continuationDepth, until it returns false. The agent’s Max Continuation Depth setting bounds the chain, so it always terminates.

A continuation is a real model call. It consumes credits and runs the same validation as /message — master switch, API key, session, per-session and per-hour rate limits, and the daily credit cap — so it can return 429 with RATE_LIMITED or CREDIT_LIMIT. It also refreshes the session’s idle timer, exactly as a message does.

POST /chat/v1/history

Returns up to 100 messages from the session’s conversation, oldest first. Useful when the widget reconnects after a refresh and needs to restore the visible thread.

Request body

{
  "clientKey":    "<your api key>",
  "sessionToken": "<from /init>"
}

Response (200 OK)

{
  "messages": [
    { "role": "user",      "content": "…", "timestamp": "2026-04-25T08:55:12.000Z" },
    { "role": "assistant", "content": "…", "timestamp": "2026-04-25T08:55:14.000Z" }
  ]
}

Error Responses

All errors share the same shape:

{
  "error": "<localised user-facing message>",
  "code":  "<machine-readable code>"
}

Use code for programmatic decisions in your client; show error to the end user.

HTTP Code Meaning
403DISABLEDThe External Bot master switch is off.
401INVALID_API_KEYAPI key is missing, malformed, or revoked.
403ORIGIN_NOT_ALLOWEDThe caller’s origin is not in the agent’s Allowed Origins list.
401SESSION_EXPIREDThe session token is invalid or has expired (per Session Timeout Minutes).
429RATE_LIMITEDThe session or per-agent rate limit was exceeded.
429MAX_MESSAGESThe session reached its Max Session Messages cap.
429CREDIT_LIMITThe org’s External Daily Credit Cap is exhausted, or the licence credit budget is.
400INVALID_INPUTBody parameter missing, message too long, or unknown action tool.
404GENERIC_ERRORUnknown sub-path under /chat/v1/.
500GENERIC_ERRORAn unexpected error. Details are recorded in the Incident Log; the response intentionally hides them.

Rate Limits

Each call passes through several rate limiters in order. The first two and the message cap are set per agent on the Agent Definition; the daily credit cap is org-wide, a Platform Setting shared by every external agent, so one busy bot can exhaust the day’s budget for all of them. Setting it to 0 means unlimited — not recommended on a public-facing widget.

Limit Source Default
Per session Agent Definition › Rate Limit Per Session 10 calls per session
Per hour Agent Definition › Rate Limit Per Hour 500 calls per agent per hour
Daily credit cap Platform Setting › External Daily Credit Cap 500 credits per day
Max messages per session Agent Definition › Max Session Messages 50 messages

See Platform Settings Reference for daily credit cap details.

Session Lifecycle

  • Creation: /init creates a session bound to the calling client’s IP and the validated origin.
  • Validity: sessions stay valid as long as they’re used. Activity on /message, /action or /history refreshes the session.
  • Timeout: idle sessions expire after Session Timeout Minutes on the agent (default 30). Calls with an expired session token receive SESSION_EXPIRED; the widget should call /init again.
  • Hard limits: a session ends when it hits Max Session Messages. Subsequent calls receive MAX_MESSAGES until a new session is created.

Required Configuration on the Agent

Several Agent Definition fields shape the widget’s behaviour:

Field Purpose
ChannelMust be External Widget for an external-facing agent.
External API KeyThe key the widget passes as clientKey. Generated from the Admin tab.
Allowed OriginsComma-separated list of permitted origins (e.g. https://www.example.com). Blank = any origin allowed.
Max Message LengthCap on user-message length in characters.
Session Timeout MinutesIdle timeout for sessions.
Rate Limit Per SessionPer-session call cap.
Rate Limit Per HourPer-agent hourly cap across all sessions.
Max Session MessagesHard cap on messages per session.
External Welcome MessageReturned by /init as welcomeMessage.
Mascot ImageReturned by /init as mascotImage.

Security Posture

  • Guest user execution. The API runs as the Salesforce Site’s Guest User. CRUD and FLS on that user’s profile govern what the agent and any tools can read or write.
  • API-key scoped to one agent. Each external agent has its own key; revoke and rotate per agent without affecting others.
  • Origin-allowlisted. Set Allowed Origins on every production agent. Blank means any origin can call — convenient for testing, risky for production.
  • Generic error messages. The API never echoes internal errors to clients. Hard failures are recorded in the Incident Log for admin investigation.
  • Daily credit cap. The External Daily Credit Cap is the org-wide ceiling that prevents a runaway public bot from exhausting the licence budget.

Best Practices

Use the shipped loader unless you have a reason not to. The loader handles cache-busting, header fallbacks, error rendering and the data attributes from Widget UI Customisation. Building your own client only makes sense for non-browser callers (mobile apps, server integrations).

Treat code as the source of truth. The error string is localised for end users and may change between versions. The code is stable.

Restart sessions on SESSION_EXPIRED, not on every error. The widget loader does this; custom clients should too. Don’t treat RATE_LIMITED or CREDIT_LIMIT as session problems — they need different recovery (back-off and admin attention respectively).

Set Allowed Origins for every public-facing agent. Leaving it blank in production removes a defence-in-depth layer.

Watch the daily credit cap. It’s the safety net for public-facing bots; tune it after observing real traffic.

Changes included in 1.16000

The per-agent hourly rate limit also applies during the final UTC hour of the day. External and Community APIs use a stable credit-limit error code so the intended HTTP 429 response no longer depends on the translated message.

Client upgrade checklist

Frequently Asked Questions

No. The four endpoints are the public contract. You can build your own client — mobile, desktop, voice, custom web — against the same API.

Don’t. Sessions are designed for sequential turns. Parallel calls on the same session can race against the rate limiters and the Conversation record. Wait for each /message response before sending the next.

For the configured Session Timeout Minutes (default 30) of inactivity. Each successful call refreshes the timer. Sessions also end when Max Session Messages is reached.

Because Salesforce Sites infrastructure can strip custom headers in certain proxy and CDN configurations. The body fallback is more reliable; the header form is convenient when you control the network path.

The four endpoints documented here cover the conversational flow. File uploads from external widgets follow the platform’s file-handling conventions; see the agent’s Allow File Upload setting and the File Upload guide.

The conversation persists in Salesforce. New sessions for the same end-user start a new conversation; the platform doesn’t automatically thread sessions together for guest users.

Generate the new key, update your loader script, and revoke the old key. Sessions that started under the old key continue as long as they don’t make a new call after revocation; new calls with the old key fail with INVALID_API_KEY. See API Key Management.

Next Steps

Read API Key Management for key issuance, or Community API Reference for the authenticated-portal counterpart.