Community API Reference
How It Differs From the External Widget API
The Community API and the External Widget API serve different surfaces and have different security models:
| Concern | External Widget API | Community API |
|---|---|---|
| Authentication | API key (per agent) | Authenticated portal user session (no API key) |
| Identity | Anonymous Guest User | Real Salesforce portal user |
| Session model | Opaque session token returned by /init |
Conversations linked to portal user; resumable on /init |
| CORS | Origin allowlist via Allowed Origins | Same-origin portal requests; no CORS configuration |
| Daily credit cap | External Daily Credit Cap | Community Daily Credit Cap |
| Permissions | Guest User profile | The portal user’s own profile and sharing |
Use this API when the chatbot lives behind a Salesforce Experience Cloud login. Use the External Widget API when the chatbot is on a public website.
Base URL
Served from your Experience Cloud site, under the path /services/apexrest/redaai/chat/community/v1/:
https://<your-community>.my.site.com/<site-path>/services/apexrest/redaai/chat/community/v1/
The exact host depends on your Experience Cloud configuration. Calls from inside the portal naturally use the portal’s session cookie for authentication.
Authentication
There is no API key. The endpoint trusts Experience Cloud’s session cookie to identify the calling portal user. Two consequences:
- Calls from a guest (unauthenticated) context are rejected with
AUTH_REQUIRED. - Calls from outside the portal that don’t carry the session cookie are also rejected.
This is why the Community API is naturally same-origin: the standard Experience Cloud session cookie won’t accompany cross-origin requests to the portal’s domain.
Endpoints
Six endpoints, all POST:
| Path | Purpose |
|---|---|
POST /chat/community/v1/init | Start a new conversation with an agent, or resume an existing recent one. |
POST /chat/community/v1/new | Force-start a new conversation, ignoring any recent existing one. |
POST /chat/community/v1/message | Send a user message and receive the agent’s reply. |
POST /chat/community/v1/action | Execute a confirmed action that the agent proposed. |
POST /chat/community/v1/history | Fetch the messages for a conversation. |
POST /chat/community/v1/continue | Ask the agent to narrate the outcome of actions it auto-executed on the previous turn. No new user message is sent. |
POST /chat/community/v1/init
Resolves the agent and either resumes the portal user’s most recent conversation with that agent (when one exists within the agent’s session timeout) or creates a fresh one.
Request body
{
"agentName": "support-assistant"
}
Response (200 OK)
{
"conversationId": "a0Q…",
"agentName": "support-assistant",
"displayName": "Support Assistant",
"welcomeMessage": "Hi! How can I help today?",
"mascotImage": "https://…/mascot.png",
"maxMessageLength": 2000,
"messages": [
{ "role": "user", "content": "…", "timestamp": "…" },
{ "role": "assistant", "content": "…", "timestamp": "…" }
]
}
When the response includes a non-empty messages array, the conversation was resumed; render the prior turns to preserve continuity. Otherwise the conversation is brand new.
Resume window
Resume eligibility is governed by Session Timeout Minutes on the agent definition (default 30). The platform finds the portal user’s most recently active conversation with that agent, checks that its last activity is within the timeout window, and resumes it if so.
POST /chat/community/v1/new
Forces a fresh conversation even if a recent one exists. Useful for “Start over” UI controls.
Request body
{
"agentName": "support-assistant"
}
Response (200 OK)
{
"conversationId": "a0Q…",
"agentName": "support-assistant",
"displayName": "Support Assistant",
"welcomeMessage": "Hi! How can I help today?",
"mascotImage": "…",
"maxMessageLength": 2000
}
No messages array is returned because the conversation has no history yet.
POST /chat/community/v1/message
Sends a single user message to the agent and returns the reply.
Request body
{
"conversationId": "<from /init or /new>",
"message": "What's open on my case 00012345?"
}
The platform validates that the calling portal user owns the conversation. Cross-user access is rejected.
Response (200 OK)
{
"response": "<agent reply text>",
"creditsUsed": 1.42,
"conversationId": "a0Q…",
"continuationPending": false,
"continuationDepth": 0
}
continuationPending is the flag your client must act on. When the agent
executed one or more actions during this turn, it returns true — meaning there is an
outcome it has not narrated yet. Call /continue to get that narration. Ignoring the flag leaves
the user looking at a reply that stops before the result of what just happened.
POST /chat/community/v1/action
Executes a confirmed action. Only Action tools assigned to the agent and scoped to the Community channel are accepted.
Request body
{
"conversationId": "<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>"
}
POST /chat/community/v1/continue
Asks the agent to narrate the real outcome of actions it auto-executed on the previous
/message turn. No new user message is sent. Call it whenever the previous response came back
with continuationPending: true.
Request body
{
"conversationId": "a0Q…",
"continuationDepth": 0
}
Pass back the continuationDepth you received from the previous response. Omitting it is treated
as 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 this is a loop, not a single follow-up call. Keep calling /continue,
feeding back the returned continuationDepth each time, until it comes back false.
The agent’s Max Continuation Depth setting bounds the chain, so the loop always
terminates.
A continuation is a real model call. It consumes credits and is checked against exactly
the same guards as /message — per-session rate limit, per-hour agent rate limit, and the
community daily credit cap — so it can return 429 with
RATE_LIMITED or CREDIT_LIMIT. Handle those the same way you do on
/message.
POST /chat/community/v1/history
Returns the conversation’s messages for the active portal user. Useful when the portal page reloads and needs to restore the visible thread.
Request body
{
"conversationId": "a0Q…"
}
Response (200 OK)
{
"messages": [
{ "role": "user", "content": "…", "timestamp": "…" },
{ "role": "assistant", "content": "…", "timestamp": "…" }
]
}
Error Responses
Same shape as the External Widget API:
{
"error": "<localised user-facing message>",
"code": "<machine-readable code>"
}
| HTTP | Code | Meaning |
|---|---|---|
| 403 | DISABLED | The Community Bot master switch is off. |
| 401 | AUTH_REQUIRED | The caller is unauthenticated (guest). Portal login is required. |
| 429 | RATE_LIMITED | The per-user-session or per-agent rate limit was exceeded. |
| 429 | MAX_MESSAGES | The conversation reached its Max Session Messages cap. |
| 429 | CREDIT_LIMIT | The org’s Community Daily Credit Cap is exhausted, or the licence credit budget is. |
| 400 | INVALID_INPUT | Body parameter missing, message too long, unknown action tool, or conversation not owned by the caller. |
| 404 | GENERIC_ERROR | Unknown sub-path under /chat/community/v1/. |
| 500 | GENERIC_ERROR | An unexpected error. Captured to the Incident Log; the response intentionally hides details. |
Rate Limits
Same controls as the External Widget API, with two differences:
- Per-session limits are tracked per portal user, not per opaque session token.
- The daily credit cap is the Community Daily Credit Cap Platform Setting, not the External cap.
| Limit | Source | Default |
|---|---|---|
| Per session (per portal user) | Agent Definition › Rate Limit Per Session | 10 calls per session |
| Per hour (per agent) | Agent Definition › Rate Limit Per Hour | 500 calls |
| Daily credit cap | Platform Setting › Community Daily Credit Cap | 2000 credits |
| Max messages per session | Agent Definition › Max Session Messages | 50 messages |
To lift the daily credit cap entirely, leave Community Daily Credit Cap blank or set it to
0 — both mean unlimited. It is deliberately a separate setting from the External Widget
cap, so a busy public widget can never exhaust the budget your portal members rely on.
Conversation Ownership
Conversations are owned by the portal user who started them. The platform validates ownership on every /message, /action and /history call — calling with a conversationId belonging to another user is rejected with INVALID_INPUT.
This is the security boundary that lets the Community API run without API keys: the portal user’s own permissions and ownership govern what they can see and do.
The portal user’s Contact is supplied to the agent automatically. Experience Cloud
users are linked to a Contact record through User.ContactId. When a conversation is created by
/init or /new, REDA AI resolves that Contact and stores it as the conversation’s
context record, then injects it into the system prompt on every subsequent turn. The agent therefore knows
who it is talking to — name, account, and whatever other Contact fields you configured as context
— without the client sending any identifying data, and without any per-agent setup.
A portal user with no Contact (rare, but possible for some Experience Cloud licence types) simply gets a conversation with no context record. Nothing fails.
Required Configuration on the Agent
| Field | Purpose |
|---|---|
| Channel | Must include Community for the agent to be reachable from the portal endpoint. |
| Max Message Length | Cap on user-message length in characters. |
| Session Timeout Minutes | Window in which /init resumes a recent conversation rather than creating a new one. |
| Rate Limit Per Session | Per-portal-user call cap. |
| Rate Limit Per Hour | Per-agent hourly cap across all portal users. |
| Max Session Messages | Hard cap on messages per conversation. |
| External Welcome Message | Shown to the portal user on conversation start. Same field as the External Widget channel. |
| Mascot Image | Avatar displayed in the portal chat. |
Security Posture
- Authentication is the portal’s. No API keys to issue, rotate or leak. Every call inherits the portal user’s session.
- Permissions are the portal user’s. CRUD, FLS and sharing rules on the portal user’s profile govern what the agent and any tools can read or write — including which records they can see in the conversation history.
- Ownership is enforced on every call. A portal user cannot read another portal user’s conversations even if they obtain the conversation ID.
- Tool channel scoping applies. Only Action tools whose Channels include
Communityare usable here. - Daily credit cap is the safety net. The Community Daily Credit Cap prevents a runaway portal bot from exhausting the licence budget.
- Generic error messages. Internal error details are never echoed; failures are recorded in the Incident Log for admin investigation.
Best Practices
Use the shipped community bridge component. The Lightning component for Experience Cloud handles the API calls, session resumption and UI rendering. Building a custom client only makes sense for non-portal contexts.
Resume rather than restart. Calling /init at the start of every page view is the right default — the platform will resume the recent conversation transparently. Reserve /new for explicit user-driven “Start over” controls.
Set a sensible Session Timeout. Too short and users lose context across page loads; too long and stale conversations resume when users intended a fresh start. The default 30 minutes is a reasonable starting point.
Watch the Community Daily Credit Cap. It’s independent of the External cap and tunable per the volume of authenticated portal users you serve.
Confirm tool channel scoping. An Action tool that’s only assigned to Internal won’t fire from a portal call — even if the agent is configured for it.
Review conversation continuity
A blank Conversation Window (Hours) now uses the organisation default, initially 30 minutes. A positive value sets the agent's window; 0 disables automatic resume. Matching remains channel-specific: API uses agent and record context; authenticated Internal/MCP uses agent, user and the relevant record context. Community uses the shared window setting instead of the external-session timeout. Home, app-page and utility-bar chat can resume eligible conversations. Explicit conversation identifiers remain subject to their route's access checks. Review agents that relied on blank meaning a new conversation, and use 0 where that behaviour is required. Packaged permission fixes also address Internal and Community conversation access.
Frequently Asked Questions
No. The endpoint relies on the Experience Cloud session cookie. Authenticated portal users can call it directly; guest users cannot.
The endpoint returns AUTH_REQUIRED for any unauthenticated caller. If your portal allows guest browsing, hide the chatbot UI for unauthenticated users; alternatively, deploy the External Widget for guest scenarios.
The conversation persists. When the same user logs back in within the Session Timeout Minutes window, /init resumes it. Outside that window, a new conversation is created.
No. Each conversation is owned by the user who started it and ownership is enforced on every call. A portal user cannot read another portal user’s conversation even with the conversation ID.
It returns prior messages only when resuming an existing conversation within the Session Timeout window. For a brand-new conversation the messages array is empty.
No. They’re two independent caps configured separately in Platform Settings.
Add a button that calls /new instead of /init. The new endpoint forces a fresh conversation regardless of any recent existing one.
Next Steps
Read Community Agent Setup for the deployment walkthrough, or External Widget API Reference for the unauthenticated counterpart.