diff --git a/api/build.gradle b/api/build.gradle
index bad823ac19d26cd4b9f17b6467b948e39535fe43..4ed4fc3a2b728eb7cb19b9df3132e8def80592c9 100644
--- a/api/build.gradle
+++ b/api/build.gradle
@@ -8,7 +8,13 @@ repositories {
     mavenCentral()
 }
 
+def telegram_version = '5.7.1'
+def junit_version = '5.8.2'
+def lombok_version = '1.18.22'
+def log4j_version = '1.2.17'
+
 dependencies {
+    implementation project(":base")
     implementation 'org.mongodb:mongodb-driver-sync:4.4.1'
     implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
     implementation 'org.springframework.boot:spring-boot-starter-data-rest'
@@ -19,12 +25,26 @@ dependencies {
     implementation 'org.hibernate:hibernate-core:5.6.5.Final'
     implementation 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final'
     implementation 'org.springframework.data:spring-data-mongodb:3.3.1'
+
+    // Telegram api
+    implementation "org.telegram:telegrambots:$telegram_version"
+    implementation "org.telegram:telegrambotsextensions:$telegram_version"
+
+    // Lombok
+    implementation "org.projectlombok:lombok:$lombok_version"
+    annotationProcessor "org.projectlombok:lombok:$lombok_version"
+
+    // Logger log4j
+    implementation "log4j:log4j:$log4j_version"
+
+    // Test spring dependencies
     testImplementation 'org.springframework.boot:spring-boot-starter-test'
     testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'
     testImplementation 'org.springframework.security:spring-security-test'
 
-    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
-    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
+    // Junit tests
+    testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_version"
+    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_version"
 }
 
 test {
diff --git a/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/BaseTextBotHandler.java b/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/BaseTextBotHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..f8c8b0f60ebb6ee85a22fbc7189ea8746816d7d1
--- /dev/null
+++ b/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/BaseTextBotHandler.java
@@ -0,0 +1,44 @@
+package cz.cvut.fit.sp.bot_builder.text_bot;
+
+import cz.cvut.fit.base.bot_builder.base.base_bot.BaseTextHandlerInterface;
+import cz.cvut.fit.base.bot_builder.base.base_bot.ChatBotTextAnswer;
+import cz.cvut.fit.base.bot_builder.base.base_bot.UserRequest;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
+import org.telegram.telegrambots.meta.api.objects.Message;
+
+import java.util.Map;
+import java.util.Optional;
+
+@Getter
+@Setter
+@RequiredArgsConstructor
+public class BaseTextBotHandler implements BaseTextHandlerInterface {
+
+    @NonNull
+    private Map<UserRequest, ChatBotTextAnswer> botCommands;
+
+    @Override
+    public Optional<SendMessage> executeRequest(String chatId, String username, Message message) {
+        // Try to find user request in available requests list
+        Optional<Map.Entry<UserRequest, ChatBotTextAnswer>> request
+                = botCommands
+                .entrySet()
+                .stream()
+                .filter((req) -> req.getKey().equals(new UserRequest(message.getText()))).findFirst();
+        if (request.isEmpty()) {
+            // Request not found...
+            return Optional.empty();
+        }
+
+        return produceAnswer(request.get(), chatId);
+    }
+
+    @Override
+    public Optional<SendMessage> produceAnswer(Map.Entry<UserRequest, ChatBotTextAnswer> requestOptional, String chatId) {
+        return Optional.ofNullable(requestOptional.getValue().convertToMessage(chatId));
+    }
+}
diff --git a/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/TelegramTextBot.java b/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/TelegramTextBot.java
new file mode 100644
index 0000000000000000000000000000000000000000..80ef185dd676da64dce1bb5ba86539d6b4ebf49d
--- /dev/null
+++ b/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/TelegramTextBot.java
@@ -0,0 +1,54 @@
+package cz.cvut.fit.sp.bot_builder.text_bot;
+
+import cz.cvut.fit.base.bot_builder.base.base_bot.BaseTelegramBot;
+import cz.cvut.fit.base.bot_builder.base.base_bot.ChatBotTextAnswer;
+import cz.cvut.fit.base.bot_builder.base.base_bot.UserRequest;
+import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
+import org.telegram.telegrambots.meta.api.objects.Message;
+import org.telegram.telegrambots.meta.api.objects.Update;
+import org.telegram.telegrambots.meta.api.objects.User;
+import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TelegramTextBot extends BaseTelegramBot {
+
+    private final BaseTextBotHandler textBotHandler;
+
+    public TelegramTextBot(Map<UserRequest, ChatBotTextAnswer> commands, String botName, String token) {
+        super(botName, token);
+        this.textBotHandler = new BaseTextBotHandler(commands);
+    }
+
+    public TelegramTextBot(String botName, String token) {
+        super(botName, token);
+        this.textBotHandler = new BaseTextBotHandler(new HashMap<>());
+    }
+
+    @Override
+    public void processNonCommandUpdate(Update update) {
+        Message message = update.getMessage();
+
+        SendMessage answer = textBotHandler
+                .executeRequest(message.getChatId().toString()
+                        , getUsername(message), message)
+                .orElse(new SendMessage());
+
+        try {
+            execute(answer);
+        } catch (TelegramApiException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    private String getUsername(Message message) {
+        User user = message.getFrom();
+        String username = user.getUserName();
+        if (username == null) {
+            return defaultUsername;
+        }
+        return username;
+    }
+}
diff --git a/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/TextBotFactory.java b/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/TextBotFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..149e0845109acdf8785968ab650557db937a1939
--- /dev/null
+++ b/api/src/main/java/cz/cvut/fit/sp/bot_builder/text_bot/TextBotFactory.java
@@ -0,0 +1,25 @@
+package cz.cvut.fit.sp.bot_builder.text_bot;
+
+import cz.cvut.fit.base.bot_builder.base.base_bot.BaseBotFactory;
+import cz.cvut.fit.base.bot_builder.base.base_bot.BotType;
+import cz.cvut.fit.base.bot_builder.base.base_bot.ChatBotTextAnswer;
+import cz.cvut.fit.base.bot_builder.base.base_bot.UserRequest;
+import lombok.AllArgsConstructor;
+import org.telegram.telegrambots.extensions.bots.commandbot.TelegramLongPollingCommandBot;
+
+import java.util.Map;
+
+@AllArgsConstructor
+public class TextBotFactory implements BaseBotFactory<TelegramLongPollingCommandBot> {
+
+    private Map<UserRequest, ChatBotTextAnswer> userCommands;
+
+    public TelegramLongPollingCommandBot getBot(BotType type, String botName, String token) {
+        switch (type) {
+            case TEXT_BOT:
+                return new TelegramTextBot(userCommands, botName, token);
+            default:
+                throw new IllegalStateException("Such bot type is not acceptable%s".formatted(type));
+        }
+    }
+}
diff --git a/base/build.gradle b/base/build.gradle
index df216b08ccc36da3c74d18d4adc6bf1fb1cdf1e7..3753ad48ee4216d7a1c5de5f3a81eb3f2a2841a2 100644
--- a/base/build.gradle
+++ b/base/build.gradle
@@ -6,10 +6,25 @@ repositories {
     mavenCentral()
 }
 
+def telegram_version = '5.7.1'
+def lombok_version = '1.18.10'
+def log4j_version = '1.2.17'
+
 dependencies {
     implementation 'org.hibernate:hibernate-core:5.6.5.Final'
     implementation 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final'
     implementation 'org.springframework.data:spring-data-mongodb:3.3.1'
+
+    // Telegram api
+    implementation "org.telegram:telegrambots:$telegram_version"
+    implementation "org.telegram:telegrambotsextensions:$telegram_version"
+
+    // Lombok
+    implementation "org.projectlombok:lombok:$lombok_version"
+
+    // Logger log4j
+    implementation "log4j:log4j:$log4j_version"
+
     testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
     testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
 }
diff --git a/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseBotFactory.java b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseBotFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..f059286956a0d18717ed3f5fe547664faff0693b
--- /dev/null
+++ b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseBotFactory.java
@@ -0,0 +1,7 @@
+package cz.cvut.fit.base.bot_builder.base.base_bot;
+
+import org.telegram.telegrambots.extensions.bots.commandbot.TelegramLongPollingCommandBot;
+
+public interface BaseBotFactory<T extends TelegramLongPollingCommandBot> {
+    T getBot(BotType type, String botName, String token);
+}
diff --git a/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseTelegramBot.java b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseTelegramBot.java
new file mode 100644
index 0000000000000000000000000000000000000000..62882daf1ea10dda614d778fa585b6019782ca2d
--- /dev/null
+++ b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseTelegramBot.java
@@ -0,0 +1,48 @@
+package cz.cvut.fit.base.bot_builder.base.base_bot;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.telegram.telegrambots.extensions.bots.commandbot.TelegramLongPollingCommandBot;
+import org.telegram.telegrambots.meta.api.objects.Update;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+
+@Getter
+@Setter
+public abstract class BaseTelegramBot extends TelegramLongPollingCommandBot {
+
+    protected static final Logger logger = Logger.getLogger(BaseTelegramBot.class.toString());
+
+    protected static final String defaultUsername = "Unknown";
+
+    private final String botName;
+    private final String token;
+
+    protected BaseTelegramBot(String botName, String token) {
+        this.botName = botName;
+        this.token = token;
+    }
+
+    @Override
+    public String getBotUsername() {
+        return botName;
+    }
+
+
+    @Override
+    public String getBotToken() {
+        return token;
+    }
+
+    @Override
+    public void onRegister() {
+        super.onRegister();
+    }
+
+    @Override
+    public void onUpdatesReceived(List<Update> updates) {
+        super.onUpdatesReceived(updates);
+    }
+}
diff --git a/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseTextHandlerInterface.java b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseTextHandlerInterface.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d13301d88ac8dddd882ca821ad950fe08a51ccf
--- /dev/null
+++ b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BaseTextHandlerInterface.java
@@ -0,0 +1,21 @@
+package cz.cvut.fit.base.bot_builder.base.base_bot;
+
+import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
+import org.telegram.telegrambots.meta.api.objects.Message;
+
+import java.util.Map;
+import java.util.Optional;
+
+public interface BaseTextHandlerInterface {
+    /**
+     * Identify user response and execute its command
+     *
+     * @param message - sender's request
+     */
+    Optional<SendMessage> executeRequest(String chatId, String username, Message message);
+
+    /**
+     * Produce answer for user command
+     */
+    Optional<SendMessage> produceAnswer(Map.Entry<UserRequest, ChatBotTextAnswer> requestOptional, String chatId);
+}
diff --git a/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BotType.java b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BotType.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb8418f86f5f6eb4afb826c2230d1d32b2c9f0a0
--- /dev/null
+++ b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/BotType.java
@@ -0,0 +1,5 @@
+package cz.cvut.fit.base.bot_builder.base.base_bot;
+
+public enum BotType {
+    TEXT_BOT
+}
diff --git a/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/ChatBotTextAnswer.java b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/ChatBotTextAnswer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0dc8b5c7d64dd86ba316b05891b0b160c7eca089
--- /dev/null
+++ b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/ChatBotTextAnswer.java
@@ -0,0 +1,21 @@
+package cz.cvut.fit.base.bot_builder.base.base_bot;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
+
+import javax.validation.constraints.NotNull;
+
+@Getter
+@Setter
+@RequiredArgsConstructor
+public record ChatBotTextAnswer(@NotNull String answer) {
+    public SendMessage convertToMessage(@NotNull String chatId) {
+        SendMessage msg = new SendMessage();
+        msg.setChatId(chatId);
+        msg.setText(answer);
+        return msg;
+    }
+
+}
diff --git a/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/UserRequest.java b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/UserRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0923e7b8031fb2418be41d5312a3d03a09bba83
--- /dev/null
+++ b/base/src/main/java/cz/cvut/fit/base/bot_builder/base/base_bot/UserRequest.java
@@ -0,0 +1,11 @@
+package cz.cvut.fit.base.bot_builder.base.base_bot;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@RequiredArgsConstructor
+public record UserRequest(String textRequest) {
+}
diff --git a/settings.gradle b/settings.gradle
index 3a06b4cb4c17cec90c01c5664c847bf0d19cb6b6..513851ed4e29d3b7d3127ea8a73f30d54e2c2ad9 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,4 +1,3 @@
 rootProject.name = 'bot_builder'
 include 'base', 'api', 'authentication'
-include 'authentication'