Integrations
API Reference
REST API for the HelpStack dashboard, widget, and webhooks.
Quick facts#
| Base path | Endpoints live under https://helpstack.eu/api/… — a path prefix, not a reachable URL |
| Auth (dashboard API) | NextAuth session cookie (logged-in user) |
| Auth (widget API) | None (public, rate-limited) |
| Auth (webhooks) | Verify-token handshake + HMAC-SHA256 signature |
| Content-Type | application/json (file uploads use multipart/form-data) |
| Tenancy | Every dashboard request is scoped to the session user's organization |
Expect a 404 on
/apiitself, and 401 on authenticated endpoints. There is no route at the barehttps://helpstack.eu/api— it returns 404 by design, because the API is a set of sub-paths (/api/conversations,/api/channels, …), not a browsable root. Opening a real endpoint like/api/conversationsin a browser returns 401 (no session cookie), which confirms it exists and is auth-protected. Neither response is a bug.
Authentication model — read this first#
There is currently no public API-key or bearer-token system for third-party callers. Do not look for an "API key" — none exists. The dashboard/internal API is authenticated with the NextAuth session cookie of a logged-in user, and every request is automatically scoped to that user's organization by middleware (
withOrganization/withAdmin/withAgent). These endpoints are consumed by the HelpStack dashboard UI.
To call dashboard endpoints from outside the browser you must replay an authenticated session cookie. If you need machine-to-machine access, the supported public surfaces are:
- Widget endpoints — public, IP/visitor rate-limited (see Widget Embed).
- Webhook endpoints — public, verified by token + HMAC signature (see Webhooks).
Treat anything requiring a session cookie as "verify against your deployment" for programmatic use.
Response envelope#
All API routes return a standard envelope.
Success
{ "success": true, "data": { } }
Error
{
"success": false,
"error": {
"message": "Human-readable message",
"code": "OPTIONAL_CODE",
"fields": { "fieldName": ["error 1"] }
}
}
code and fields are optional. fields is populated for validation errors (Zod) with per-field messages.
Error codes & HTTP status#
Errors are produced by typed error classes and a central handler. High-level mapping:
| HTTP | When | Example code |
|---|---|---|
| 400 | Invalid input / validation failure | VALIDATION_ERROR |
| 401 | Missing or expired auth | — |
| 402 | Insufficient tokens to perform the action | INSUFFICIENT_TOKENS |
| 403 | Insufficient role/permission | — |
| 404 | Resource not found | — |
| 409 | Duplicate/conflict | — |
| 429 | Rate limit hit | — |
| 502 | Third-party API failure | — |
| 500 | Unexpected/internal error (message is masked) | — |
Zod validation failures return 400 with code: "VALIDATION_ERROR" and a fields object. Unexpected errors return 500 with a generic message ("An unexpected error occurred"); the real detail is logged server-side only.
Endpoint catalog#
Roles: an endpoint marked ADMIN requires admin (withAdmin), AGENT requires agent-or-higher (withAgent), Session requires any authenticated org member (withOrganization).
Channels
| Method | Path | Purpose | Auth |
|---|---|---|---|
GET | /api/channels | List channels | Session |
POST | /api/channels | Create channel | ADMIN |
GET | /api/channels/[id] | Get one channel | Session |
PATCH | /api/channels/[id] | Update channel | ADMIN |
DELETE | /api/channels/[id] | Delete channel | ADMIN |
GET | /api/channels/[id]/widget-script | Get embed script for a WEBSITE_CHAT channel | Session |
GET | /api/channels/[id]/widget-config | Get widget appearance config | Session |
GET/POST | /api/channels/[id]/agent-tools | List/attach channel-scoped agent tools | Session |
Create channel — POST /api/channels (verified body, createChannelSchema):
{
"type": "WEBSITE_CHAT",
"name": "Website Chat",
"region": "eu",
"defaultLanguage": "en",
"autoTranslate": true,
"translateToLanguage": "en",
"fallbackLanguage": "sl",
"aiProviderId": "PROVIDER_ID",
"credentials": {},
"responseTemplate": {},
"autoReply": false,
"autoApprove": false,
"autoEnhance": false
}
| Field | Type | Required | Notes |
|---|---|---|---|
type | enum | yes | EMAIL | FACEBOOK | INSTAGRAM | WHATSAPP | TELEGRAM | WEBSITE_CHAT |
name | string | yes | Min length 1 |
region | string | no | |
defaultLanguage | string | no | Default en (agent language) |
autoTranslate | boolean | no | Default true |
translateToLanguage | string | no | Agent language to translate to |
fallbackLanguage | string | no | Customer language guess for short/ambiguous messages |
aiProviderId | string | no | Falls back to the org default provider |
credentials | object | yes | Channel-specific credentials (e.g. IMAP/SMTP, page tokens) |
responseTemplate | object | no | |
autoReply | boolean | no | Default false |
autoApprove | boolean | no | Default false |
autoEnhance | boolean | no | Default false |
Channel-type credential shapes (credentials) are validated separately — e.g. Email requires { host, port, username, password, from, secure?, imapHost?, imapPort?, imapSecure?, imapAllowSelfSigned? }; Facebook requires { pageId, accessToken, appSecret? }; Instagram requires { accountId, accessToken }. Credentials are stored encrypted (AES-256-GCM).
Conversations
| Method | Path | Purpose | Auth | Key params |
|---|---|---|---|---|
GET | /api/conversations | List conversations | Session | page, pageSize, status, channelId, unread, assignedToId, language, search |
POST | /api/conversations | Create conversation | AGENT | |
GET | /api/conversations/[id] | Get one | Session | |
PATCH | /api/conversations/[id] | Update (status, priority, assignment, language, notes) | Session | |
DELETE | /api/conversations/[id] | Delete | Session | |
GET | /api/conversations/[id]/messages | List messages | Session | |
POST | /api/conversations/[id]/messages | Send agent reply | AGENT | |
POST | /api/conversations/[id]/read | Mark read | Session | |
POST | /api/conversations/[id]/unread | Mark unread | Session | |
POST | /api/conversations/bulk-read | Mark many read | Session |
status filter values: OPEN | PENDING | CLOSED | ARCHIVED. pageSize is capped at 100 (default 20).
Send message — POST /api/conversations/[id]/messages (verified body, sendMessageSchema):
{
"conversationId": "CONVERSATION_ID",
"content": "Thanks for reaching out — here's how to fix that.",
"attachments": ["storage/path/file.png"]
}
| Field | Type | Required | Notes |
|---|---|---|---|
conversationId | string | yes | Must equal the [id] route param, else 400 VALIDATION_ERROR |
content | string | yes | Min length 1 |
attachments | string[] | no | Storage paths |
Behavior: the message is created OUTBOUND. If the channel has autoTranslate on and a customer language is known, the message is created unapproved and translated in the background (the agent approves before it is sent). Sending consumes plan tokens; if the org is out of tokens the route returns 402 with code: "INSUFFICIENT_TOKENS". Success returns the created message with HTTP 201.
Messages
| Method | Path | Purpose | Auth |
|---|---|---|---|
POST | /api/messages/[id]/approve | Approve a queued/translated reply for sending | Session |
POST | /api/messages/[id]/generate-reply | Generate an AI reply suggestion | Session |
POST | /api/messages/[id]/retranslate | Re-run translation for the message | Session |
FAQs
| Method | Path | Purpose | Auth | Key params |
|---|---|---|---|---|
GET | /api/faqs | List FAQs | Session | channelId |
POST | /api/faqs | Create FAQ | ADMIN | |
PATCH | /api/faqs/[id] | Update FAQ | Session | |
DELETE | /api/faqs/[id] | Delete FAQ | Session | |
POST | /api/faqs/reorder | Reorder FAQs | Session | |
POST | /api/faqs/generate | AI-generate FAQ suggestions | Session |
Media
| Method | Path | Purpose | Auth |
|---|---|---|---|
POST | /api/media/upload | Upload a file (multipart/form-data) | Session |
GET | /api/media/[id] | Fetch media metadata/file | Session |
DELETE | /api/media/[id] | Delete media | Session |
Notifications
| Method | Path | Purpose | Auth |
|---|---|---|---|
GET/PUT | /api/notifications/preferences | Get/update notification preferences | Session |
GET/POST | /api/notifications/integrations | List/configure notification integrations | Session |
POST | /api/notifications/push-subscription | Register a Web Push subscription | Session |
AI providers
| Method | Path | Purpose | Auth |
|---|---|---|---|
GET | /api/ai-providers | List configured providers | Session |
POST | /api/ai-providers | Add a provider | Session |
PATCH | /api/ai-providers/[id] | Update a provider | Session |
DELETE | /api/ai-providers/[id] | Remove a provider | Session |
Agent tools
| Method | Path | Purpose | Auth |
|---|---|---|---|
GET | /api/agent-tools | List org-level agent tools | Session |
POST | /api/agent-tools | Create an agent tool | Session |
PATCH | /api/agent-tools/[id] | Update an agent tool | Session |
DELETE | /api/agent-tools/[id] | Delete an agent tool | Session |
GET | /api/agent-tools/[id]/logs | View tool-call logs | Session |
See Custom Agent Tools for the full tool anatomy.
Widget (public)
| Method | Path | Purpose | Auth |
|---|---|---|---|
GET | /api/widget/[channelId]/config | Widget config | Public, ~30/min/IP |
GET | /api/widget/[channelId]/faqs | Up to 5 FAQ chips | Public, ~30/min/IP |
GET | /api/widget/[channelId]/status | Online status | Public |
POST | /api/widget/[channelId]/upload | File upload | Public |
POST | /api/widget/message | Send message (WebSocket fallback) | Public, ~20/min/visitor |
See Widget Embed for payloads.
Webhooks (public)
| Method | Path | Purpose | Auth |
|---|---|---|---|
GET | /api/webhooks/facebook | Verify handshake | Verify token |
POST | /api/webhooks/facebook | Receive Messenger events | HMAC signature |
GET/POST | /api/webhooks/instagram | Verify / receive Instagram events | Verify token / HMAC |
GET/POST | /api/webhooks/whatsapp | Verify / receive WhatsApp events | Verify token / HMAC |
See Webhooks for handshake and signature details.