Integration guide
Plug a remembering agent into anything
EverDesk exposes your trained support agent two ways: a drop-in website widget and a REST API for your own product surfaces. Both share the same memory - a customer who chats on your site is recognized in your app.
Quickstart
- Onboard your company - name it and provide docs (pasted text, URLs, or files). Provisioning takes under two minutes.
- Copy your public key (looks like pk_yourcompany_xxxxxxxx). It is safe to expose, like an analytics ID.
- Install the widget or call the API - below.
Website widget
One script tag before the closing body tag. It renders a floating chat bubble; the chat itself runs in an isolated iframe, so your site styles are never touched.
<script
src="https://everdesk.allensaji.dev/embed.js"
data-everdesk-key="pk_yourcompany_xxxxxxxx"
async>
</script>Visitors get a persistent identity in their browser; when they share an email, memory follows them across devices and sessions.
REST API
The widget uses this same endpoint. Call it from your backend, mobile app, in-product help panel, or a Slack bot. CORS is open; authenticate with your public key.
POST https://everdesk.allensaji.dev/api/v1/chat
Content-Type: application/json
{
"key": "pk_yourcompany_xxxxxxxx", // required
"visitorId": "user-123", // required, your stable user id
"email": "customer@example.com", // optional, upgrades memory identity
"sessionId": "everdesk-...", // optional, returned by first call
"message": "How do refunds work?" // required
}Response:
{
"answer": "Refunds are processed within 7 days...",
"grounded": true,
"sessionId": "everdesk-acme-1a2b3c-1783150000000",
"customerId": "cust_2b88ecea",
"latencyMs": 7578
}- Reuse the returned sessionId for the rest of one conversation; drop it to start a new one. Memory persists either way.
- Keep visitorId stable per user (a database id works). Same visitorId means same remembered customer.
- grounded is false when the agent could not answer from your knowledge - a good signal to escalate to a human.
Actions & webhooks
Actions let the agent do things, not just answer: file a ticket, ping your team, hit your API. You describe in plain English when an action should fire and which fields the agent must collect; when a conversation matches, EverDesk POSTs a signed JSON payload to your webhook and tells the customer what it did. Every fired action is written into that customer's memory, so next week the agent remembers what it already did for them.
Configure actions in your dashboard under Actions. Point the URL at your own endpoint, or at Zapier / Make / n8n to reach email, Slack, CRMs and everything else without writing code. (Slack and Discord incoming webhooks expect their own payload shape, so route those through one of the automation tools.)
POST <your webhook URL>
Content-Type: application/json
X-Everdesk-Timestamp: 1783150000
X-Everdesk-Signature: sha256=3f5c...9d21
{
"action": "create_refund_ticket",
"test": false,
"company": { "slug": "acme", "name": "Acme" },
"customer": {
"customerId": "cust_2b88ecea",
"email": "customer@example.com"
},
"params": { "order_id": "4711" },
"conversation": {
"sessionId": "everdesk-acme-1a2b3c-1783150000000",
"message": "I want a refund for order 4711",
"answer": "I've filed that refund for you..."
},
"firedAt": "2026-07-04T12:00:00.000Z"
}Verify the signature before trusting a payload. The signature is an HMAC-SHA256 of timestamp + "." + rawBody using the signing secret shown once when you created the action. Reject requests older than 5 minutes to block replays:
import { createHmac, timingSafeEqual } from "node:crypto";
function verifyEverdesk(rawBody, headers, secret) {
const ts = headers["x-everdesk-timestamp"];
const sig = headers["x-everdesk-signature"]; // "sha256=<hex>"
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = "sha256=" + createHmac("sha256", secret)
.update(ts + "." + rawBody)
.digest("hex");
return expected.length === sig.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}- When an action fires, the chat response gains an action: { "name", "status": "fired" } field and the receipt is appended to the answer.
- Only https URLs resolving to public addresses are accepted, and redirects are never followed.
- Rate limits apply: 5 fires per customer per hour, 100 per company per day, and duplicate fires within 60 seconds are dropped.
React
Embed the chat surface directly in any React app:
export function SupportChat() {
return (
<iframe
src="https://everdesk.allensaji.dev/widget?key=pk_yourcompany_xxxxxxxx"
style={{ width: 380, height: 600, border: 0, borderRadius: 16 }}
title="Support chat"
/>
);
}Or build a fully custom UI on the REST API above - the widget has no special powers.
Forget API
Wire right-to-be-forgotten into your own account deletion flow. This hard-deletes the customer's memory items from the graph and vector store.
POST https://everdesk.allensaji.dev/api/companies/{slug}/customers/{customerId}/forget
// -> { "status": "forgotten", "deleted": 4 }Verify it in the dashboard: the customer's memory graph drops to zero nodes.
Questions?
The whole product is open source: github.com/Allen-Saji/everdesk