payload-support
A complete, self-hosted support & ticketing system for Payload CMS 3 + Next.js — tickets, SLA, AI assists and an autonomous AI agent, live chat, a full client portal, time tracking & invoicing, and a visual automation-rules engine. No third-party support SaaS required.

Table of Contents
- Features
- Quick Start
- Installation
- Usage
- API Reference
- Configuration
- Performance
- Examples
- FAQ
- Troubleshooting
- Security
- Contributing
- Changelog
- Roadmap
- Support
- License

Features
Complete ticketing Statuses, priorities, categories, tags, merge/split, snooze, scheduled replies, internal notes, an immutable activity log and a keyboard-driven Superhuman-style inbox. |
SLA & automation SLA policies (business hours + pause-on-hold), escalation, macros, round-robin, and a visual automation-rules engine (conditions → actions). |
Built-in AI Sentiment, reply suggestions, multi-style rewriting, cached synthesis, a KB chatbot, and an autonomous AI agent that answers or escalates. Anthropic, OpenAI or self-hosted Ollama. |
Omnichannel & portal Inbound/outbound email, live chat (SSE), widget, a full client portal (auth, 2FA, Google OAuth), knowledge base and deflection. |
Time tracking & billing Timer, manual entries, time dashboard, per-project pre-billing and a print-ready invoice (HTML → PDF). |
Reporting & privacy Real-time dashboard, CSAT + NPS, email tracking, HMAC-signed webhooks, notification digests, CSV exports. 100% self-hostable. |

Quick Start
// payload.config.ts
import { buildConfig } from 'payload'
import { supportPlugin } from '@consilioweb/payload-support'
export default buildConfig({
plugins: [
supportPlugin({
features: { ai: true, sla: true, timeTracking: true, chat: true },
ai: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
locale: 'fr',
}),
],
})pnpm payload generate:importmap
pnpm devOpen /admin/support/inbox for the agent inbox, or /support for the client portal. The plugin injects collections, API endpoints and admin views automatically — no external SaaS.

Installation
npm
npm install @consilioweb/payload-supportyarn
yarn add @consilioweb/payload-supportpnpm
pnpm add @consilioweb/payload-supportPeer dependencies: payload@^3, react@^18 || ^19, react-dom@^18 || ^19, next@^14 || ^15 || ^16. lucide-react and the @payloadcms/* packages are optional depending on the features you enable. After adding admin components, run pnpm payload generate:importmap.

Usage
Basic
// All features are on by default — turn off what you don't need:
supportPlugin({ features: { chat: false, pendingEmails: false }, locale: 'en' })Advanced
supportPlugin({
features: { ai: true, sla: true, roundRobin: true, webhooks: true, snooze: true },
ai: { provider: 'ollama', model: 'qwen2.5', baseUrl: process.env.OLLAMA_API_URL },
email: { fromName: 'Support ACME', fromAddress: 'support@acme.com', replyTo: 'support@acme.com' },
allowedEmailDomains: ['acme.com'], // restrict OAuth auto-registration
collectionSlugs: { tickets: 'support-tickets' }, // slug overrides
navGroup: 'Support',
basePath: '/support',
})Run the AI agent on a ticket
await fetch('/api/support/ai-agent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ticketId, confidenceThreshold: 0.7 }),
})
API Reference
supportPlugin(config)
The Payload plugin. Adds collections, admin views, editor components and API endpoints.
supportPlugin(config?: SupportPluginConfig): PluginExports
import { supportPlugin, generateTicketSynthesis, dispatchWebhook } from '@consilioweb/payload-support'
import type { SupportPluginConfig, SupportFeatures } from '@consilioweb/payload-support'Key HTTP endpoints (under /api/support)
| Method | Path | Purpose |
|---|---|---|
POST |
/ai |
Sentiment, reply suggestion, rewrite, synthesis (admin). |
POST |
/ai-agent |
Autonomous AI agent — answers from the KB or escalates. |
POST |
/login, /2fa, /oauth/google |
Client portal auth (password, 2FA, OAuth). |
GET |
/admin-stats |
Dashboard KPIs (real volume series, CSAT, NPS). |
GET |
/billing, /billing/invoice |
Pre-billing + print-ready invoice. |
POST |
/process-snooze, /process-digests, /process-scheduled, /auto-close |
Cron jobs (guarded by x-cron-secret). |

Configuration
| Option | Type | Default | Description |
|---|---|---|---|
features |
SupportFeatures |
all true |
Toggle each feature on/off. |
ai |
AIProviderConfig |
anthropic |
AI provider: anthropic | openai | ollama | custom. |
email |
EmailConfig |
— | fromName, fromAddress, replyTo. |
locale |
'fr' | 'en' |
'fr' |
Admin/portal language. |
basePath |
string |
'/support' |
Admin views prefix. |
userCollectionSlug |
string |
'users' |
Agents collection. |
allowedEmailDomains |
string[] |
— | Domains allowed for OAuth auto-registration. |
collectionSlugs |
object |
— | Collection slug overrides. |
skipCollections / skipViews / skipEndpoints |
boolean |
false |
Skip injecting that part. |
Environment variables
| Env var | Required | Description |
|---|---|---|
PAYLOAD_SECRET |
Payload secret (also signs 2FA & tracking). | |
NEXT_PUBLIC_SERVER_URL |
Public URL (email/portal links). | |
CRON_SECRET |
for crons | x-cron-secret header for the cron endpoints. |
ANTHROPIC_API_KEY / OLLAMA_API_URL |
if AI | AI provider keys/URL. |
GOOGLE_OAUTH_CLIENT_ID / _SECRET |
if OAuth | Portal Google sign-in. |
VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY |
if push | Web Push keys (npx web-push generate-vapid-keys). |
VAPID_SUBJECT |
optional | Push contact (mailto: or URL), defaults to mailto:support@example.com. |
SUPPORT_TEAM_SCOPING |
optional | 1 to scope agents to their team's tickets. |
SUPPORT_EMAIL / SUPPORT_REPLY_TO |
optional | From/reply-to addresses. |

Performance
Engineered to stay fast under load (no fabricated benchmarks — figures depend on your volume and host):
| Concern | Approach |
|---|---|
| Settings reads | In-process cache (TTL + invalidation) — avoids ~8 redundant DB reads per ticket mutation. |
| List queries | SQLite indexes on filtered fields — inbox/dashboard/SLA in O(index) instead of full scans. |
| Email sends | Fire-and-forget — the response no longer waits on the SMTP round-trip (−200-500 ms). |
| Stats & billing | Paginated aggregation + bounded select — never loads all tickets in memory. |
| AI synthesis | Cached per ticket — no LLM recompute on every view. |

Examples
Automation rule (no code)
Create a Automation Rules entry: event = ticket_created, condition category = bug, action set_priority = urgent. New "bug" tickets become "urgent" automatically.
Wire the cron jobs
# Hourly: auto-close, snooze wake-up, scheduled replies
curl -X POST https://your-app/api/support/auto-close -H "x-cron-secret: $CRON_SECRET"
curl -X POST https://your-app/api/support/process-snooze -H "x-cron-secret: $CRON_SECRET"
# Daily / weekly: notification digests
curl -X POST https://your-app/api/support/process-digests -H "x-cron-secret: $CRON_SECRET" -d '{"frequency":"daily"}'
FAQ
Which databases are supported?
Built and tested on SQLite (@payloadcms/db-sqlite) with a sequential seed and busyTimeout. It works with any Payload adapter, but indexes and queries were validated on SQLite.
What Node / Payload versions are supported?
Node.js 18+, Payload 3.x, React 18 or 19.
Is there TypeScript support?
Yes — strict TypeScript, with business types exported (SupportPluginConfig, SupportFeatures, …).
Do I need an external AI service?
No. AI features are optional and you can run self-hosted Ollama to depend on no cloud (sovereignty/GDPR). Anthropic and OpenAI are also supported.
How do I migrate the schema in production?
In standalone mode the schema isn't auto-migrated: generate/push the schema (new fields and collections) before deploying. See Troubleshooting.

Troubleshooting
useServerFunctions must be used within ServerFunctionsProvider
Use Payload 3.75+ for all @payloadcms/* packages (aligned versions).
SQLITE_BUSY / database is locked during seed
Make the seed sequential (no Promise.all on inserts) and add busyTimeout: 10000 to the SQLite adapter.
Admin views don't load
Regenerate the import map after adding components: pnpm payload generate:importmap. In a plugin/headless context, use skipViews: true if you don't mount the admin UI.
New fields/collections missing in production
Standalone doesn't run migrations: push the schema for googleId, twoFactorVerifiedAt, slaPausedAt, nps, mentions, and the notification-queue / automation-rules collections.

Security
Security is a first-class concern — several guardrails are validated by integration tests.
- Cross-client isolation — a client can never read another's tickets/messages (filtered by owned tickets).
- 2FA enforced server-side (
beforeLogin); OAuth verifies the Google email. - Sanitization of message HTML server-side (stored-XSS protection).
- HMAC-signed webhooks, signed tracking pixel, fail-closed secrets.
Reporting Security Issues
Please email contact@consilioweb.fr instead of opening a public issue.
Best Practices
- Set a strong
PAYLOAD_SECRET(never a default value) - Set
CRON_SECRETto protect the cron endpoints - Restrict read access to the
mediacollection to the ticket owner - Put the app behind a trusted proxy (
x-forwarded-forheader) - Keep the plugin up-to-date

Contributing
Contributions are very welcome!
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'feat: add AmazingFeature') - Push the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Run the checks before submitting:
npm run typecheck && npm test && npm run build
Changelog
See CHANGELOG.md for the full history.
[1.1.0] — 2026-06-25
- Per-team SLA policies & dashboards (team policy overrides the default,
?teamId=scoping). - Native push / browser notifications (Web Push / VAPID, agent pushed on new client messages).
- End-to-end UI test harness (browser-driven admin via Playwright,
pnpm test:e2e). - 109 integration tests (up from 102).
[1.0.0] — 2026-06-25
- Complete ticketing, SLA (+ pause-on-hold), automation & visual rules engine.
- AI (sentiment, suggestion, synthesis, chatbot) + autonomous AI agent.
- Live chat, client portal (2FA, OAuth), knowledge base.
- Time tracking, pre-billing & print-ready invoice.
- CSAT + NPS, real volume series, digests, webhooks.
- Security hardening (cross-client isolation, anti-XSS, server-side 2FA).
- Integration test harness (Payload + in-memory SQLite), 102 tests.
Previous versions (0.x)
- 0.16.0 — Manual client reminder + auto-close after 24h
- 0.15.0 — Next 16 compatibility + accumulated features
- 0.9.0 → 0.9.13 — Enriched views (Client Intelligence, Billing), bundled RichTextEditor, code blocks in emails, inline message editing, enriched pre-billing, per-ticket cached AI synthesis, multi-style rewriting
- 0.6.0 → 0.6.4 — Split build (
bundle:false) for Next.js RSC compatibility + barrel exports - 0.5.0 — Full i18n across the 13 admin views
- 0.4.0 — Per-user preferences (locale, signature) vs global settings
- 0.3.0 — Feature parity with ConsilioWEB +
skipCollections/skipViews/skipEndpoints - 0.2.0 — 2026-04-08 — Security overhaul, SSE live chat, webhooks, SLA, scheduled replies, client portal
- 0.1.0 — 2026-04-08 — Initial scaffold:
supportPlugin(), 15 collections, feature flags, AI provider abstraction

Roadmap
- Ticketing, SLA, time tracking & billing
- AI assists + autonomous AI agent
- Live chat, client portal, knowledge base
- Visual automation-rules engine
- Native binary PDF invoice (alongside the print-ready HTML)
- Full admin i18n (all views)
- Social channels (WhatsApp, Messenger)
- Multi-team / workspaces mode
- Per-team SLA policies & dashboards
- Native push / browser notifications
- End-to-end UI test harness (browser-driven admin)

Support
If this plugin saves you time, consider buying me a coffee!

License
Licensed under the MIT License. See the LICENSE file for details.

Built and maintained by ConsilioWEB