For Developers.

Build custom WhatsApp chatbots with the QSoft.CxPerium .NET SDK — from installation and dialogs to NLP, messaging, WhatsApp Flows and platform modules.

01. Installation and Configuration

Set up a CxPerium-based chatbot from scratch: create your account, download the sample project, run it behind a reverse proxy and connect it to the platform.

  1. Create an account or log in

    Visit app.cxperium.com. Sign up with your full name, email address and password, then verify the activation email — or use Sign In if you already have an account.

  2. Download the sample project from GitHub

    Navigate to the CxPerium.BotTemplate repository and review the project description. Click the Code button, then either download the ZIP or clone with HTTPS.

  3. Add the NuGet package

    Add the CxPerium private NuGet package QSoft.CxPerium to the project.

  4. Review the project structure and default settings

    The project runs on http://localhost:3978/ by default. Modify launchSettings.json if you need to change the port.

  5. Set up a reverse proxy

    A reverse proxy (ngrok) is required to route WhatsApp messages to your local machine. Note the generated public URL (e.g. https://xxxxx.ngrok.io/).

  6. Add the ngrok URL and developer settings to the project

    Locate appsettings.json and update the BotUrl and HookUrl fields. Then go to Settings > API Integration in CxPerium, click Regenerate to create an API key, and add it to the file.

  7. Test the setup

    Send "Hello" to the WhatsApp sandbox number +90 850 309 45 52 — the bot responds with "Hello World". You can also use the direct link https://web.whatsapp.com/send/?phone=908503094552&text=hi. Your CxPerium-based chatbot is now successfully running.

terminal
# Clone the sample project
git clone https://github.com/cxperium/CxPerium.BotTemplate.git

# Route WhatsApp messages to your local machine
ngrok http 3978 --host-header="localhost:3978"
appsettings.json
{
  "BotUrl": "https://xxxxx.ngrok.io",
  "HookUrl": "https://hook.example.com",
  "ApiKey": "your_generated_api_key_here"
}

02. Assistant Project Template

The Assistant sample project ships with a clear structure: a Channels directory, a Dialogs directory, the appsettings.json configuration file and the Program.cs entry point.

project structure
CxPerium.BotTemplate/
├── Channels/
│   ├── CxPerium.cs
│   └── Whatsapp.cs
├── Dialogs/
│   └── MainDialog.cs
├── appsettings.json
└── Program.cs

Channels folder

The CxPerium.cs class captures events from the CxPerium platform:

  • OnSurveyCompleted — triggered when a survey finishes.
  • OnClosingLiveChat — triggered when an agent closes a live chat.
  • OnSessionTimeOut — triggered after no user messages arrive for the configured duration (5 minutes by default).

The Whatsapp.cs class processes incoming messages and events:

  • OnDialogFlowMessage and OnChatGPTMessage — NLP-routed message events.
  • OnFileReceived, OnOrderReceived, OnLocationReceived — media, order and location events.
  • GetContactByPhone — retrieves the sender's information.
  • OnUnderstandMessage — the default fallback response.

This file should not be modified unless necessary; its methods can be overridden for special requirements.

Dialogs folder

The Dialogs folder contains the MainDialog.cs file. Create all of your dialogs here for better code organization and scalability.

Configuration

The appsettings.json file stores the API keys and webhook information obtained from CxPerium.

03. Creating a Dialog

Dialogs manage the flow of interactions between a user and the bot and form the foundation of the user experience. This section details the steps to create a dialog for a chatbot using the QSoft.CxPerium .NET SDK.

What is a dialog?

A dialog is a logical structure that defines how a chatbot responds to user queries or handles a workflow. In the QSoft.CxPerium SDK, dialogs are programmed within a defined logic framework to achieve the desired outcomes.

Core dialog components

  • Contact — represents the user sending the message, corresponding to an entry in the CxPerium Contacts list.
  • Activity — an object that defines the type and value of the received message.
  • Conversation — an object that stores temporary data throughout the conversation.

Example dialog: "Who are you?"

We will create a dialog where, when a user sends the message "who are you", the bot responds with "I am a special assistant". Create a folder named Dialogs in your project and add a new C# class file named WhoAreYouDialog. The class must inherit from BaseWhatsAppDialog, implement the IWhatsAppDialog interface and implement the RunDialog method it requires.

WhoAreYouDialog.cs
using QSoft.CxPerium.Dialogs.WhatsApp;

namespace QSoft.CxPerium.Assistant.Dialogs
{
    public class WhoAreYouDialog : BaseWhatsAppDialog, IWhatsAppDialog
    {
        public void RunDialog()
        {
            this.Messages.SendMessage("I am a special assistant");
        }
    }
}

Mapping the dialog in CxPerium

  1. Log in to CxPerium

    Open the platform and navigate to Assistant > Dialog page.

  2. Create a new dialog

    Click the New Dialog button.

  3. Enter the dialog details

    Dialog Name: the full namespace (e.g. QSoft.CxPerium.Assistant.Dialogs.WhoAreYouDialog). Report Name: a descriptive name for reporting. Language: the recognition language. Regex Value: the trigger pattern ("who are you").

  4. Save

    Click Save to register the dialog.

Summary of steps

  1. Define a class named WhoAreYouDialog.
  2. Extend the BaseWhatsAppDialog class.
  3. Implement the IWhatsAppDialog interface.
  4. Write the response logic in the RunDialog method.
  5. Send messages using Messages.SendMessage.
  6. Register and configure the dialog in the CxPerium platform.

04. CxPerium NLP Structure and Configuration

CxPerium employs three distinct approaches to understand user messages and direct them to the appropriate dialogs.

1. Matching with Regex

Messages conforming to Regex expressions are routed to the relevant dialogs and progress based on the predefined rules. It is recommended to define Regex rules that match the most frequently sent user messages.

2. Google Dialogflow integration

When a message has no Regex match, the system checks the DialogFlowConfig settings on the Assistant > Configuration screen. When IsEnabled: true is configured, the message proceeds to Google Dialogflow, which analyzes the message semantics and generates a response or returns a suggested action. This integration requires the Dialogflow API keys and project details.

3. ChatGPT integration

If Regex matching fails and Dialogflow yields no appropriate response, CxPerium references the ChatGPTConfig settings. When IsEnabled: true, the message is routed to ChatGPT, which directly analyzes it using an AI-powered natural language processing model. This integration requires API keys, model selection and parameter definitions.

Summary flow

  1. Regex — patterns direct matching messages to the relevant dialogs.
  2. Dialogflow — processes unmatched messages when enabled.
  3. ChatGPT — handles the remaining messages when enabled.

This cascade ensures messages are processed through multiple control mechanisms and handled using the most appropriate method.

05. Google Dialogflow Configuration

Connect Google Dialogflow to your assistant so unmatched messages are analyzed semantically and routed to the right dialogs.

  1. Log in to Google Dialogflow and create an agent

    Access the Dialogflow Console and create an agent (for example "DemoAgent" in Turkish). Open the agent settings and navigate to the Google Cloud project settings via the Project ID link.

  2. Create a service account

    In Google Cloud, open the Service Accounts menu, create a new service account with the Owner role and generate a JSON key file. Store the file securely.

  3. Integrate CxPerium with the project

    In CxPerium, go to Assistant > Configuration and edit the DialogFlowConfig field. Place the JSON key file in the project root directory and configure it to be copied during builds.

  4. Test and validate

    Create an intent with a text response in Dialogflow, then send the associated training phrase via WhatsApp to verify the configuration works.

The DialogFlowConfig field requires:

  • CredentialsFilePath — the JSON key filename (e.g. demoagent-xxxxx.json).
  • ProjectId — the project_id value from the JSON file.
  • IsEnable — set to True.

Matching an intent with a dialog

Add a custom payload to the Dialogflow intent to map it to a dialog class:

custom-payload.json
{
  "intent": "QSoft.CxPerium.Assistant.Dialogs.DialogFlowDemoDialog"
}
DialogFlowDemoDialog.cs
using QSoft.CxPerium.Dialogs.WhatsApp;

namespace QSoft.CxPerium.Assistant.Dialogs
{
    public class DialogFlowDemoDialog : BaseWhatsAppDialog, IWhatsAppDialog
    {
        public void RunDialog()
        {
            this.Messages.SendMessage("This dialog is mapped from DialogFlow");
        }
    }
}

Parameters captured by Dialogflow can be read inside the dialog:

capturing-parameters.cs
public void RunDialog()
{
    var country = this.Parameters["country"];
    this.Messages.SendMessage($"Country parameter: {country}");
}

06. ChatGPT Configuration

Configure the ChatGPT integration so messages that Regex and Dialogflow cannot handle are answered by an OpenAI assistant.

  1. Log in to the OpenAI platform or create an account

    Open your browser and go to https://platform.openai.com/. If you already have an OpenAI account, click Log In; otherwise click Sign Up to create a new one.

  2. Create an assistant on the OpenAI platform

    After logging in, go to the Assistants menu, click Create New Assistant and configure the assistant according to your requirements.

  3. Copy the Assistant ID and generate an API key

    Open the details page of the assistant you created and copy the Assistant ID. Then navigate to the API Keys section, click Create New API Key and store the generated key securely — it will be used during the integration with CxPerium.

  4. Edit the ChatGPTConfig information in CxPerium

    In the CxPerium platform, go to the Assistant section and open the Configuration screen. Configure the ChatGPTConfig settings: enter the ApiKey and AssistantId values obtained from the OpenAI platform and set the IsEnabled field to True.

After completing these steps, your ChatGPT integration with CxPerium will be ready.

08. Localization Settings

The localization module contains settings that allow the assistant to display messages sent via the chatbot in different languages.

The localization menu is accessible via Assistant > Localization. It lets you define localization keys and their corresponding values across different languages. Within your project, the Localization class retrieves the values of these keys.

MainDialog.cs
using QSoft.CxPerium.Dialogs.WhatsApp;
using QSoft.CxPerium.Models;
using QSoft.CxPerium.WhatsApp;

namespace QSoft.CxPerium.Assistant.Dialogs
{
    public class MainDialog : WelcomeDialog
    {
        public override void RunDialog()
        {
            string message = this.Localization.GetLocalizationText("SessionTimeoutMessage");
        }
    }
}

The GetLocalizationTextByLanguage method translates text into a specific language:

by-language.cs
string message = Localization.GetLocalizationTextByLanguage("SessionTimeoutMessage", LanguagesEnum.Turkish);
  • LanguagesEnum represents the target language with predefined supported options.
  • Unsupported languages trigger a NotImplementedException.
  • Messages are determined based on the dialogue language detected from the user's input.

09. Messaging

The messaging methods of the CxPerium .NET SDK for WhatsApp communication. All methods are accessed through the Messages object, available when inheriting from the BaseWhatsAppDialog class.

SendMessage

Sends text-based messages, with optional URL preview.

send-message.cs
this.Messages.SendMessage("Hello World");
this.Messages.SendMessage("Hello CXPerium https://www.cxperium.com", true);

SendButtonMessage

Delivers a message with interactive buttons (a maximum of three buttons is allowed).

send-button-message.cs
public class DemoDialog : BaseWhatsAppDialog, IWhatsAppDialog
{
    public void RunDialog()
    {
        List<Button> buttons = new List<Button>();
        buttons.Add(new Button() { IsVisible = true, Reply = new Reply() { Title = "Yes Button", Id = "#yes_button" } });
        buttons.Add(new Button() { IsVisible = true, Reply = new Reply() { Title = "No Button", Id = "#no_button" } });
        this.Messages.SendButtonMessage("Hello World", "Header Text", "Footer Text", buttons);
    }
}

SendImageMessage

Three variants for image delivery: local file, media ID or URL.

send-image-message.cs
FileInfo file = new FileInfo("C:\\images\\example.jpg");
this.Messages.SendImageMessageByFile(file, "Here is an image");

string mediaId = "123456789";
this.Messages.SendImageMessageById(mediaId, "Here is an image");

Uri url = new Uri("https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png");
this.Messages.SendImageMessageByUrl(url, "Here is an image");

SendLocationMessage

Transmits geographic coordinates with location details.

send-location-message.cs
this.Messages.SendLocationMessage(40.712776, -74.005974, "New York", "New York, NY, USA");

SendDocumentMessage

Three variants for document delivery: file, media ID or URL.

send-document-message.cs
FileInfo file = new FileInfo("C:\\documents\\example.pdf");
this.Messages.SendDocumentMessageByFile(file, "Here is a document", "example.pdf");

string mediaId = "987654321";
this.Messages.SendDocumentMessageById(mediaId, "Here is a document", "example.pdf");

Uri link = new Uri("https://example.com/documents/example.pdf");
this.Messages.SendDocumentMessageByUrl(link, "Here is a document", "example.pdf");

SendVideoMessage

Three variants for video delivery: file, media ID or URL.

send-video-message.cs
FileInfo file = new FileInfo("C:\\videos\\example.mp4");
this.Messages.SendVideoMessageByFile(file, "Here is a video");

string mediaId = "654321987";
this.Messages.SendVideoMessageById(mediaId, "Here is a video");

Uri url = new Uri("https://example.com/videos/example.mp4");
this.Messages.SendVideoMessageByUrl(url, "Here is a video");

SendListMessage

Delivers interactive list messages with rows and/or sections.

send-list-message.cs
List<Row> rows = new List<Row>
{
    new Row() { Id = "1", Title = "Option 1", Description = "Description for option 1" },
    new Row() { Id = "2", Title = "Option 2", Description = "Description for option 2" }
};
this.Messages.SendListMessage("Choose an option", "Header Text", "Footer Text", "View Options", rows);

List<Section> sections = new List<Section>
{
    new Section()
    {
        Title = "Section 1",
        Rows = new List<Row>
        {
            new Row() { Id = "1", Title = "Option 1", Description = "Description for option 1" },
            new Row() { Id = "2", Title = "Option 2", Description = "Description for option 2" }
        }
    }
};
this.Messages.SendListMessage("Choose an option", "Header Text", "Footer Text", "View Options", sections);

09.1. Messaging (Advanced)

Additional messaging methods: location requests, contact cards, stickers, emoji reactions and catalog / product messages.

SendLocationMessage

Shares a specific location with the user via coordinates and address details. Parameters: lat (double), lon (double), name (string, e.g. "Office") and address (string).

send-location.cs
SendLocationMessage(double lat, double lon, string name, string address);

SendLocationMessage(40.987654, 29.123456, "QSoft Office", "Istanbul, Turkey");

SendLocationRequest

Requests the user's current location via WhatsApp. The parameter is the request message text.

send-location-request.cs
this.Messages.SendLocationRequest("Please share your location.");

SendContact

Transmits a contact card containing phone, name, email and professional details.

send-contact.cs
SendContact(string phoneNumber, string name, string surname, string email,
string company, string department, string title);

SendContact("+905001112233", "Ahmet", "Yılmaz",
"ahmet.yilmaz@example.com", "QSoft", "Software", "Engineer");

SendSticker

Sends sticker files to users in WebP format.

send-sticker.cs
SendSticker(string stickerUrl);

SendSticker("https://example.com/sticker.webp");
  • Static stickers — 512×512 pixels, maximum 100 KB.
  • Animated stickers — 512×512 pixels, maximum 500 KB.
  • Format — WebP only; EXIF and metadata must be removed.
  • Conversion — CloudConvert can convert PNG/JPEG files to WebP.

SendEmoji

Adds or removes an emoji reaction on a message. A single emoji is allowed per reaction; sending an empty string removes the previous emoji. Android/iOS compatible emojis and processed emojis are supported.

send-emoji.cs
SendEmoji(string messageId, string emoji);

SendEmoji("1234567890", "😊");
SendEmoji("1234567890", "");

SendCatalog

Displays the linked product catalog in WhatsApp. Parameters: the catalog message content and the footer text.

send-catalog.cs
SendCatalog(string message, string footer);

SendCatalog("Discover our products!", "Contact us for more information.");

SendProductMessage

Transmits individual product details from the Meta catalog. The parameter is the product's unique Meta catalog identifier. The product must first be added to the Meta catalog before its details can be sent.

send-product-message.cs
this.Messages.SendProductMessage("1");

SendMultipleProductMessage

Sends multiple product listings in a single organized message.

send-multiple-product-message.cs
SendMultipleProductMessage(string bodyText, string footerText,
string headerText, List<MultiProductSection> products);

var products = new List<MultiProductSection>
{
  new MultiProductSection
  {
    Title = "Group 1",
    Items = new List<MultiProductItem>
    {
      new MultiProductItem { ProductRetailerId = "12345" },
      new MultiProductItem { ProductRetailerId = "67890" }
    }
  }
};

this.Messages.SendMultipleProductMessage("Body text", "Footer text",
"Header text", products);

10. WhatsApp Flows

How to use WhatsApp Flows in the CxPerium SDK for custom WhatsApp chatbots.

What is WhatsApp Flows?

WhatsApp Flows is a business messaging feature that enables structured interactions. Instead of a traditional chat, it provides a form-like interface without leaving WhatsApp — delivering a seamless user experience, organized data collection and efficient information gathering.

  • Structured interactions — planned, organized communication models.
  • Enhanced forms — data collection beyond text-based messaging.
  • Stay within WhatsApp — users share information without external redirects.
  • Faster interaction — structured processes save time.
  • Improved user experience — an intuitive data-collection interface.

Sending a Flow message

The this.Messages.SendFlowMessage method sends WhatsApp Flows messages and has multiple overloads:

send-flow-message-overloads.cs
// Usage 1
SendFlowMessage(string message, string headerText, string footerText,
  string buttonText, Type catchedDialog, string flowIdOrName, string screen)

// Usage 2
SendFlowMessage(string message, Uri url, string footerText,
  string buttonText, Type catchedDialog, string flowIdOrName, string screen)

// Usage 3
SendFlowMessage(string message, Uri url, string footerText,
  string buttonText, Type catchedDialog, string flowIdOrName, string screen, JObject data)

// Usage 4
SendFlowMessage(string message, string headerText, string footerText,
  string buttonText, Type catchedDialog, string flowId, string screen, JObject data)

Capturing Flow data

The dialog that will capture the form data must derive from BaseWhatsAppDialog and implement the IFlowReceiveMessage interface:

UserFormHandlerDialog.cs
using Newtonsoft.Json.Linq;
using QSoft.CxPerium.Dialogs.WhatsApp;

namespace QSoft.CxPerium.Assistant.Dialogs
{
  public class UserFormHandlerDialog : BaseWhatsAppDialog, IFlowReceiveMessage
  {
    public void ReceiveFlowMessage()
    {
      JObject formValue = this.Activity.Form.ResponseJson;
      // Process form data here.
    }
  }
}

Example Flow usage

A dialog that opens the form:

MainDialog.cs
using QSoft.CxPerium.Dialogs.WhatsApp;
using System;

namespace QSoft.CxPerium.Assistant.Dialogs
{
  public class MainDialog : WelcomeDialog
  {
    public override void RunDialog()
    {
      this.Messages.SendFlowMessage(
        "Fill out the form below for your support request.",
        "Form",
        "Your request will be answered as soon as possible.",
        "Open Form",
        typeof(UserFormHandlerDialog),
        "customer_support",
        "DETAILS"
      );
    }
  }
}

A dialog that captures the form data:

UserFormHandlerDialog.cs
using Newtonsoft.Json.Linq;
using QSoft.CxPerium.Dialogs.WhatsApp;

namespace QSoft.CxPerium.Assistant.Dialogs
{
  public class UserFormHandlerDialog : BaseWhatsAppDialog, IFlowReceiveMessage
  {
    public void ReceiveFlowMessage()
    {
      JObject formValue = this.Activity.Form.ResponseJson;
      Messages.SendMessage($"The order form entered is {formValue["screen_0_Order_number_1"]} types");
    }
  }
}

Using endpoints in Flows

Configure the bot URL below as the Flow endpoint — it manages screen transitions and form dynamics:

endpoint
https://yourboturl/api/CxPerium/flows

To handle the data_exchange action, implement the IFlowDataExchange interface:

data-exchange.cs
public class UserFormHandlerDialog : BaseWhatsAppDialog, IFlowDataExchange
{
  public FlowResponse DataExchange(FlowRequest request)
  {
    var exchangeData = request.Data;
    var response = new FlowResponse();
    response.Screen = "another_screen";
    response.Action = "navigate";
    return response;
  }
}

Generating RSA keys for WhatsApp Flows

A 2048-bit RSA key is required for secure data exchange — see the WhatsApp Business Encryption Guide for details. Add the private key file to the project:

  1. File name

    Name the file private.pem.

  2. Build action

    Set the file's Build Action to Embedded resource.

With this framework in place, CxPerium enables businesses to leverage WhatsApp Flows for structured and efficient customer interactions.

11. CxPerium Modules

An overview of the CxPerium modules and their integration into WhatsApp chatbots using C#. CxPerium offers four main modules — Live Chat, Survey, CRM and Ticket — each with distinct functionality for customer interaction.

Live Chat

Enables real-time customer support and instant responses to user inquiries. Transfer a conversation to live chat from any dialog:

transfer-to-live-chat.cs
using QSoft.CxPerium.Dialogs.WhatsApp;
using System;

namespace QSoft.CxPerium.Assistant.Dialogs
{
  public class MainDialog : BaseWhatsAppDialog
  {
    public override void RunDialog()
    {
      this.LiveChat.TransferToLiveChat();
    }
  }
}

Transfer the conversation to a specific team:

transfer-by-team.cs
string teamId = "TEAM_ID_HERE";
this.LiveChat.TransferToLiveChatByTeam(teamId);

Handle the webhook fired when a live chat is closed:

on-closing-live-chat.cs
protected override void OnClosingLiveChat(Contact contact)
{
  base.OnClosingLiveChat(contact);
}

Survey

Designed to measure user experience and collect customer feedback on satisfaction and needs. Survey webhooks let you react to answers and completions:

survey-webhooks.cs
protected override void OnSurveyQuestionAnswered(Contact contact,
  ConversationState conversation, SurveyCx survey,
  SurveyQuestionReplyCx answer)
{
  base.OnSurveyQuestionAnswered(contact, conversation, survey, answer);
}

protected override void OnSurveyCompleted(Contact contact,
  ConversationState conversation, SurveyCx survey)
{
  base.OnSurveyCompleted(contact, conversation, survey);
}

Send a survey from the assistant:

send-survey.cs
this.Survey.SendSurvey("surveyid");

CRM

Manages customer relationships and stores customer interaction records. Records are created automatically when users message the linked WhatsApp number with GDPR consent. Access the contact data from any dialog:

contact-access.cs
var user = this.Contact;
// Access user.Id, user.Phone, user.Email, etc.

The Contact class also provides these methods:

  • InsertOrUpdateCustomField(string fieldName, string fieldValue)
  • Anonymize()
  • UpdateEmail(string email)
  • UpdateLanguage(LanguagesEnum language)

Ticket

A task management system that lets users create support tickets via assistants. Tickets can be assigned to CxPerium users or teams, with WhatsApp notifications.

Couldn't find what you're looking for?

Let our technical team guide you through your integration — send us your question and we'll get back to you the same day.

Dedicated technical support · Free integration consulting