DChat 2.0 Installation Guide

Self-hosted live chat with real-time messaging, AI chatbot, and modern dashboard.

System Requirements

ComponentRequirement
Runtime.NET 8 ASP.NET Core Runtime Required
DatabaseSQL Server 2014+ (Express edition is fine) Required
OSWindows Server 2016+, Windows 10+, or Linux
RAM1 GB minimum, 2 GB recommended
Disk200 MB for application, database grows with usage

Installation Steps

1 Install .NET 8 Runtime

Download and install the ASP.NET Core Runtime 8.0 from:

https://dotnet.microsoft.com/download/dotnet/8.0

Choose the Hosting Bundle if deploying on IIS, or the ASP.NET Core Runtime for standalone deployment.

2 Create Database

Create a blank database on your SQL Server instance:

CREATE DATABASE DChat;

Then run the schema script to create all tables:

sqlcmd -S YOUR_SERVER -d ZChat -i install-source\ZCHAT-APP-DB.sql

This creates the 14 base tables (SupportSession, SupportMessage, SupportAgent, SupportDepartment, SupportFeedback, SupportCustomer, SupportMissChat, User, SampleUsers, Settings, Portal, Rule, LogMessage, AgentOnline). The server creates the remaining feature tables (contacts, labels, channels, help center, automation and so on) automatically on first start.

Then insert default accounts:

sqlcmd -S YOUR_SERVER -d ZChat -i install-source\seed-data.sql

This creates a default admin and agent account so you can log in immediately.

3 Configure Connection String

Edit Web\appsettings.json and update the connection string:

{
  "ConnectionStrings": {
    "DChat": "Server=YOUR_SERVER;Database=ZChat;Trusted_Connection=true;TrustServerCertificate=true"
  }
}
Note: For SQL Authentication, use: Server=YOUR_SERVER;Database=ZChat;User Id=sa;Password=YOUR_PASSWORD;TrustServerCertificate=true
License: None is needed. Without a Web\dchat.lic file DChat runs as the free Community edition with unlimited agents. If you have a Premium or Enterprise licence, place it at Web\dchat.lic in the application root.
Restart required: After adding or replacing Web\dchat.lic, restart the DChat server before signing in to the dashboard.

4 Start the Server

Fast local smoke test

run-local.cmd

This helper starts the packaged server on http://127.0.0.1:5050 using .\SQLEXPRESS and zchatdemo by default. Use it when you want a quick developer test without editing files first.

Option A: Standalone (recommended for testing)

cd Web
dotnet DChat.Web.dll --urls "http://0.0.0.0:5000"

Option B: Windows Service

sc create DChatServer binPath="C:\DChat\Web\DChat.Web.exe --urls http://0.0.0.0:5000"
sc start DChatServer
Upgrading from ZChat (2.0.8 and earlier): the server program is now DChat.Web.exe / DChat.Web.dll (was ZChat.Web). Point an existing service at it - sc stop ZChatServer, sc config ZChatServer binPath= "C:\ZChat\Web\DChat.Web.exe --urls http://0.0.0.0:5000", sc start ZChatServer - or, for IIS with your own web.config, change ZChat.Web to DChat.Web in it. Then delete the old ZChat.*.dll/.exe/.pdb files from Web: while they are there, anything still starting ZChat.Web runs the old version. Licence files, connection strings, the database, widget embeds and webhook receivers keep working unchanged; see READ_ME.txt for the full list.

Option C: IIS (with Hosting Bundle)

  1. Create an IIS website pointing to the Web folder
  2. Set the Application Pool to "No Managed Code"
  3. Ensure the app pool identity has database access

Option D: Docker

docker-compose up -d

The bundled Docker compose file creates the database (named ZChat, as before the product was renamed, so an upgraded install keeps its data) and applies the schema automatically on first startup.

5 Open the Dashboard

Navigate to http://YOUR_SERVER:5000/dashboard in your browser.

Default credentials (created by seed-data.sql):

RoleUsernamePassword
Adminadminadmin123
Agentagent1agent123
Important: the first sign-in with either account must set a new password before anything else works; the dashboard asks for it. You can create additional agents from the Dashboard > Agents page.

6 Add Chat Widget to Your Website

Add one of these snippets before the closing </body> tag on your website:

Option A: Self-initializing (recommended)

<script src="http://YOUR_SERVER:5000/widget/dchat.iife.js"
        data-server-url="http://YOUR_SERVER:5000"
        data-site-id="default"
        data-greeting="Hello! How can we help you?"
        data-primary-color="#2563eb"></script>

Option B: Programmatic

<script src="http://YOUR_SERVER:5000/widget/dchat.iife.js"></script>
<script>
  DChat.init({
    serverUrl: 'http://YOUR_SERVER:5000',
    siteId: 'default',
    greeting: 'Hello! How can we help you?',
    primaryColor: '#2563eb'
  });
</script>

The chat widget will appear as a floating button in the bottom-right corner.

7 Desktop Agent Console (Optional)

The Windows desktop app is a separate download, dchat-agent-console.zip (version 2.0.10). Unzip it anywhere and run DChat.Agent.exe; the .NET runtime and the Windows App SDK are bundled. Enter your server URL and sign in. Windows 10 1809 or later, 64-bit.

It connects over SignalR and includes:

Single sign-on from the app, signatures and template variables need a 2.0.6 server. Against a 2.0.5 server the SSO button stays disabled and variables are inserted as written.

Note: The web dashboard at /dashboard provides full agent functionality in the browser without any additional installation.

Configuration

JWT Authentication

Update appsettings.json with a strong secret key:

"Jwt": {
  "SecretKey": "YOUR-SECRET-KEY-AT-LEAST-32-CHARACTERS-LONG",
  "Issuer": "DChat",
  "Audience": "DChat",
  "ExpirationMinutes": 480
}

AI Chatbot (Optional)

Configure AI chatbot in the Dashboard under Settings > AI Chatbot. Supported providers:

HTTPS / SSL

For production, always use HTTPS. Options:

Security Notes Read before going live

Upgrading from 2.0.9 to 2.0.10

Upgrading from 2.0.8 to 2.0.9

Upgrading from 2.0.7 to 2.0.8

Upgrading from 2.0.6 to 2.0.7

Upgrading from 2.0.5 to 2.0.6

Configuration Keys 2.0.5

Optional keys in Web\appsettings.json. Everything else is set from the dashboard.

KeyPurpose
Channels:SecretKeyEncrypts inbox, SSO, Slack and widget-identity secrets in the database. By default a key is generated into App_Data\channel-secrets-key. Pin one (base64 of 32 random bytes) if several instances share one database. If the file is lost, those secrets have to be entered again.
Channels:PublicBaseUrlFallback for the Public URL on the Inboxes page (the page setting wins).
Push:SubjectYour contact for push services: mailto:you@example.com or an https URL of yours. Default https://dchat.com/. Set your own.
Push:VapidPrivateKeyWeb push key (base64 PKCS#8, P-256). By default one is generated into App_Data\vapid-keys. Pin it if several instances share one database.
Push:AllowPrivateEndpointstrue allows non-https or private push endpoints. For testing only. Default false.
Webhooks:AllowPrivateTargetstrue allows webhook and API-channel callback URLs on private or local networks. Default false.
Network:TrustedProxies, Network:TrustedProxyNetworks, Network:ForwardLimitWhich reverse proxies' X-Forwarded-For headers are trusted. Empty by default.
Slack:SyncSecondsHow often new conversations are posted to Slack (1-300, default 5).
HelpCenter:ViewFlushSecondsHow often article view counts are written (default 30).
Auto-assignment is controlled by the AutoAssign.Enabled setting. You switch it on only under Automation > Auto-assignment in the dashboard, and it starts off after an upgrade. It is a Premium feature.

Public URL

Dashboard > Inboxes > Public URL is the address the internet reaches this server at, for example https://chat.example.com (no path, no query). Channels, voice and file sending all use it.

Channels (Dashboard > Inboxes)

Email inboxes are free. Every other channel needs Premium to create or change. After a lapse an existing inbox keeps receiving messages, but agents cannot reply through it; you can always switch it off. Secret fields are encrypted and never shown again. Generated values (verify tokens, inbound tokens) are shown once, when the inbox is created. Copy them then, or use rotate later to get a new one.

ChannelCredentialsWhere the webhook URL goes
TelegramBot token from @BotFather (/newbot)Save the inbox, then press Connect webhook. DChat calls Telegram's setWebhook with the URL and a generated secret, which Telegram sends back in X-Telegram-Bot-Api-Secret-Token. Needs an https Public URL.
SMS (Twilio), WhatsApp (Twilio)Account SID, Auth token (verifies X-Twilio-Signature), From number in E.164 (e.g. +14155550100) or Messaging service SIDTwilio console, on the number, messaging service or WhatsApp sender: set "A message comes in" to Webhook, HTTP POST, the inbox webhook URL. It must match the Public URL character for character.
WhatsApp Cloud API (Meta)Phone number ID, Access token (system user with whatsapp_business_messaging), App secret (verifies X-Hub-Signature-256), optional WhatsApp Business Account ID (for Sync templates)Meta app dashboard > WhatsApp > Configuration. Callback URL is the inbox webhook URL. Verify token is the generated value; DChat answers hub.challenge. Subscribe the messages field.
Facebook Messenger, Instagram DMsPage ID (Instagram: account ID), Page access token, App secretMeta app dashboard > Messenger (or Instagram) > Webhooks. Callback URL is the inbox webhook URL and Verify token is the generated value. Subscribe to messages.
LINEChannel secret (verifies X-Line-Signature), Channel access tokenLINE Developers console > Messaging API. Set Webhook URL to the inbox webhook URL, turn "Use webhook" on and auto-reply messages off. Replies use the push API and count against your LINE quota.
API (your own app)Callback URL (public http(s)); Inbound token and HMAC secret are generatedYour app POSTs to the inbox webhook URL with X-DChat-Inbox-Token (or Authorization: Bearer). Agent replies are POSTed to your Callback URL, signed as shown below.
Email freeInbound secret (generated), optional Reply-To address, mode conversation or missed_chatYour mail gateway POSTs the same JSON as /api/v1/email/inbound to the inbox webhook URL with X-DChat-Inbound-Secret. Replies go out through the SMTP server in Settings. Pass the sender-authentication verdict too (below).

Inbound email: sender authentication

A From header is whatever the sender typed. If your mail gateway knows whether a message passed SPF, DKIM and DMARC, pass the result on. Add "spf", "dkim" and "dmarc" fields (pass, fail, softfail, none...) to the JSON, or forward the receiving server's Authentication-Results header in "headers". This works for /api/v1/email/inbound and for email inboxes. DMARC decides when present. Otherwise one passing SPF or DKIM result is enough. When the verdict is present and failing, the message is not threaded onto the sender's earlier conversation or linked to their contact. It starts a new conversation marked [Sender not verified], with a private note for agents, and the response carries "senderVerified": false. Replies still go to the address the mail claimed, so a forger never sees them. With no verdict, mail is handled as before.

API channel message and reply signature:

POST /api/v1/channels/{inboxId}/webhook
X-DChat-Inbox-Token: <inbound token>
Content-Type: application/json

{"contact":{"identifier":"customer-42","name":"Jane","email":"jane@example.com"},
 "message":{"id":"your-unique-id","text":"Hello"}}

// replies to your Callback URL carry:
X-DChat-Timestamp: <timestamp>
X-DChat-Signature: sha256=HMAC-SHA256(hmac secret, timestamp + "." + body)
24-hour window: WhatsApp, Messenger and Instagram allow free-form replies only within 24 hours of the customer's last message. For WhatsApp after that, send an approved template: create it in Twilio's Content Template Builder or in Meta, press Sync templates on the inbox, and agents pick it under the reply box.

Voice (Twilio) Premium

  1. Inboxes > new inbox > Voice (Twilio). Enter the Account SID, Auth token and Phone number (E.164). Choose the Ring mode (browser, forward or browser_then_forward) and fill in Forward to, Ring for (seconds), Voicemail, Transcribe voicemail and the greeting.
  2. In the Twilio console, open the number > Voice configuration:
    A call comes in     = Webhook, HTTP POST, https://YOUR_HOST/api/v1/voice/{inboxId}/incoming
    Call status changes = https://YOUR_HOST/api/v1/voice/{inboxId}/status
  3. Browser softphone (optional): in Twilio, create an API key (SK...) and a TwiML App (AP...) whose Voice URL is https://YOUR_HOST/api/v1/voice/{inboxId}/outbound (HTTP POST). The Calls page shows the exact URLs. Paste the API key SID, API key secret and TwiML app SID into the voice inbox.
  4. Agents open Calls and press Switch softphone on to have calls ring in the browser, or use "Call via my phone" for click-to-call.
  5. Optional: Outbound destinations on the voice inbox limits the numbers agents can call to the country codes you list (for example +1, +44). Outbound calls are billed to your Twilio account; leave it empty to allow any number.

As with SMS, the Public URL must match the URLs Twilio calls exactly.

Single Sign-On Enterprise

Configure it under Dashboard > Single Sign-On.

OpenID Connect (Entra ID, Okta, Google, Keycloak, Auth0)

SAML 2.0 (ADFS, Okta, Entra ID, OneLogin, Shibboleth)

Both protocols

Help Center Free

Web Push Notifications

API Access Tokens

Widget Identity Verification and JavaScript API

  1. Go to Widget Builder > Identity validation > Generate secret. Keep the secret on your server and never put it in a page.
  2. On your server, compute identifierHash as the lower-case hex HMAC-SHA256 of the signed-in user's id, keyed with the secret string exactly as shown (do not hex-decode it):
    // Node
    const identifierHash = require('crypto').createHmac('sha256', SECRET).update(String(user.id)).digest('hex');
    // PHP
    $identifierHash = hash_hmac('sha256', $user->id, $secret);
    // C#
    var identifierHash = Convert.ToHexString(HMACSHA256.HashData(
        Encoding.UTF8.GetBytes(secret), Encoding.UTF8.GetBytes(userId))).ToLowerInvariant();
  3. In the page:
    DChat.setUser('user-4711', {
      identifierHash: '<computed on your server>',
      name: 'Ann Lee', email: 'ann@example.com', plan: 'pro'
    });

When the hash matches, agents see Verified identity and the chat is filed under that contact. Tick Ignore identities that do not verify so that a page cannot attach itself to someone else's history. Replacing the secret invalidates every hash computed with the old one.

CallWhat it does
DChat.setUser(identifier, { identifierHash, name, email, phone, ...attributes })Tells DChat who the visitor is (identifier at most 150 characters). Extra keys are stored as custom attributes.
DChat.setCustomAttributes({ plan: 'pro', seats: 12 })Sets contact attributes. null removes one.
DChat.open() / close() / toggle()Opens, closes or toggles the chat window.
DChat.reset()Forgets the user, the conversation and the visitor id. Call it on sign-out.
DChat.on(event, callback)Events: ready, open, close, message, unread. Returns an unsubscribe function.

Slack Premium

  1. Create a Slack app with the bot scopes chat:write and users:read, and install it to your workspace.
  2. Under Event Subscriptions, set the Request URL to https://YOUR_HOST/api/v1/integrations/slack/events (public HTTPS). The Integrations page shows this URL as the server sees itself, so behind a proxy use your public address instead. Subscribe to the bot events message.channels, plus message.groups for a private channel.
  3. Invite the bot to the channel. In Dashboard > Integrations, paste the Bot token (xoxb-...), the Signing secret and the Channel ID (like C0123ABCDEF, not the channel name). Optionally add a Dashboard address for links. Tick "Post new conversations to Slack and relay thread replies", save, then press Test connection.

Each new conversation becomes a Slack thread, and replies in the thread reach the customer. Only conversations that start after you switch it on are posted.

Editions and Lapses

TierIncludes
Community (free)Unlimited agents with no licence file: widget, dashboard, email and email inboxes, help center, web push, API tokens, widget identity verification, webhooks.
PremiumAI assistant, custom roles, removing "Powered by DChat", automation rules, macros, auto-assignment, per-agent chat limits, required attributes, CSAT review notes, extra channels (Telegram, WhatsApp, SMS, Messenger, Instagram, LINE, API), voice, Slack.
EnterprisePremium plus single sign-on (OIDC / SAML) and advanced SLA policies.

When paid coverage ends, the paid features switch off and nothing else does. Nothing is deleted, and agents are never locked out:

A paid feature can always be switched off on any tier; switching it on needs the tier. API refusals carry the code requires_premium or requires_enterprise. The dashboard's Plan & Licence page shows the tier in force.

API Reference

EndpointMethodDescription
/GETHealth check
/api/v1/auth/loginPOSTAgent login (returns JWT)
/api/v1/dashboard/statsGETLive dashboard statistics
/api/v1/agentsGETList agents
/api/v1/departmentsGETList departments
/api/v1/sessionsGETSearch chat sessions
/api/v1/sessions/{id}/messagesGETGet session transcript
/api/v1/settingsGETGet all settings
/hubs/chatWebSocketSignalR real-time hub
/api/docsGETFull API reference (OpenAPI document at /api/docs/openapi.json)
/api/v1/channels/{inboxId}/webhookGET/POSTChannel provider webhooks (signed per provider)

Troubleshooting