How to create a Telegram bot with AI agent support using Workflows
With serverless technologies, you can create a Telegram bot with text generation model support based on Yandex AI Studio.
In this tutorial, you will create a bot which provides movie recommendations based on user preferences. To do this, you will implement data storage in Yandex Object Storage and Yandex Lockbox, configure bot logic in Yandex Workflows and set up a webhook using Yandex API Gateway.
To create a bot:
- Get your cloud ready.
- Register your Telegram bot.
- Create a secret.
- Create a bucket.
- Create service accounts.
- Set up a workflow.
- Set up an API gateway.
- Set up a webhook for your bot.
- Test your bot.
- Customize the agent.
If you no longer need the resources you created, delete them.
Getting started
Sign up for Yandex Cloud and create a billing account:
- Navigate to the management console
and log in to Yandex Cloud or create a new account. - On the Yandex Cloud Billing
page, make sure you have a billing account linked and it has theACTIVEorTRIAL_ACTIVEstatus. If you do not have a billing account, create one and link a cloud to it.
If you have an active billing account, you can navigate to the cloud page
Learn more about clouds and folders here.
Required paid resources
The cost of Telegram bot support includes:
- Text generation fee (see Yandex AI Studio pricing).
- Fee for storing the secret and requests to the secret (see Yandex Lockbox pricing).
- Fee for the amount of stored data, number of data operations, and outbound traffic (see Yandex Object Storage pricing).
- Fee for the number of requests to the API gateway and outbound traffic (see Yandex API Gateway pricing).
- Fee for collecting and storing logs (see Yandex Cloud Logging pricing).
Register your Telegram bot
Register your bot in Telegram and get a token.
-
To register the new bot, start BotFather
and run this command:/newbot -
Specify the bot’s name, e.g.,
Serverless AI Telegram Bot. This is the name users will see when chatting with the bot. -
Specify the username of your bot, e.g.,
ServerlessAITelegramBot. You can use it to find the bot in Telegram. The username must end with...Botor..._bot.As a result, you will get a token. Save it, as you will need it later.
Create a secret
Create a secret to store the token for access to the Telegram API.
- In the management console
, select the folder where you are going to create your infrastructure. - Select Lockbox.
- Click Create secret.
- In the Name field, enter a name for the secret.
- Select the
Customsecret type. - In the Key field, enter
token. - In the Value field, specify the bot’s token you got when creating it.
- Click Create.
If you do not have the Yandex Cloud CLI installed yet, install and initialize it.
By default, the CLI uses the folder specified when creating the profile. To change the default folder, use the yc config set folder-id <folder_ID> command. You can also set a different folder for any specific command using the --folder-name or --folder-id parameter.
-
View a description of the CLI create secret command:
yc lockbox secret create --help -
Create a secret:
yc lockbox secret create \ --name tg-bot-token \ --payload '[{"key":"token","text_value":"<bot_token>"}]'Where:
-
--name: Secret name. -
--payload: Secret contents as a YAML or JSON array.key: Secret key.text_value: Secret value. Specify the token you received when creating the bot.
Result:
id: e6qf05v4ftms******** folder_id: b1g681qpemb4******** created_at: "2025-08-20T12:26:02.961Z" name: tg-bot-token status: ACTIVE current_version: id: e6q768pl3vrf******** secret_id: e6qf05v4ftms******** created_at: "2025-08-20T12:26:02.961Z" status: ACTIVE payload_entry_keys: - token -
To create a secret, use the Create REST API method for the Secret resource or the SecretService/Create gRPC API call.
Create a bucket
Create a bucket to store your chat history with the bot.
- In the management console
, select Object Storage. - In the top panel, click Create bucket.
- Enter the bucket name consistent with the naming conventions.
- Specify the maximum bucket size:
5 GB. - Click Create bucket.
-
View the description of the CLI command to create a bucket:
yc storage bucket create --help -
Create a bucket in the default folder:
yc storage bucket create \ --name <bucket_name> \ --default-storage-class standard \ --max-size 5368709120Where:
--name: Bucket name consistent with the following naming conventions.--default-storage-class: Storage class.--max-size: Maximum bucket size, in bytes.
Result:
name: bot-history-storage folder_id: b1g681qpemb4******** anonymous_access_flags: {} default_storage_class: STANDARD versioning: VERSIONING_DISABLED max_size: "5368709120" created_at: "2025-08-20T12:23:21.361186Z" resource_id: e3erbgk1qmih********
If you do not have the AWS CLI yet, install and configure it.
To create a bucket, assign the storage.editor role to the service account used by the AWS CLI.
In the terminal, run this command:
aws s3api create-bucket \
--endpoint-url=https://storage.yandexcloud.net \
--bucket <bucket_name>
Where:
--endpoint-url: Object Storage endpoint.--bucket: Bucket name consistent with the following naming conventions.
To create a bucket, use the Create REST API method for the Bucket resource, the BucketService/Create gRPC API call, or the create S3 API method.
Create service accounts
Create two service accounts:
sa-apigw: This one will be used for executing the Workflows workflow.sa-workflows: This one will be used for executing the workflow steps.
- In the management console
, select Identity and Access Management. - Click Create service account.
- Specify the service account name:
sa-apigw. - Click
Add role and select theserverless.workflows.executorrole. - Click Create.
Similarly, create a service account named sa-workflows and assign the following roles to it:
storage.uploaderstorage.viewerlockbox.payloadViewerai.languageModels.user
-
View a description of the CLI command to create a service account:
yc iam service-account create --help -
Create service accounts:
yc iam service-account create --name sa-apigw yc iam service-account create --name sa-workflowsWhere
--nameis the service account name.Result:
id: ajeu2s3k358j******** folder_id: b1g681qpemb4******** created_at: "2025-08-20T12:18:37.599632350Z" name: sa-apigw id: ajersnus6rb2******** folder_id: b1g681qpemb4******** created_at: "2025-08-20T12:18:41.869376672Z" name: sa-workflows -
Save the service account IDs and the folder ID to these variables:
APIGW_SA=$(yc iam service-account get --name sa-apigw --format json | jq -r .id) WF_SA=$(yc iam service-account get --name sa-workflows --format json | jq -r .id) FOLDER_ID=$(yc config get folder-id) -
View the description of the CLI command for assigning a role for the folder:
yc resource-manager folder add-access-binding --help -
Assign roles for the folder to the service accounts:
yc resource-manager folder add-access-binding \ --id $FOLDER_ID \ --role serverless.workflows.executor \ --subject serviceAccount:$APIGW_SA yc resource-manager folder add-access-binding \ --id $FOLDER_ID \ --role storage.uploader \ --subject serviceAccount:$WF_SA yc resource-manager folder add-access-binding \ --id $FOLDER_ID \ --role storage.viewer \ --subject serviceAccount:$WF_SA yc resource-manager folder add-access-binding \ --id $FOLDER_ID \ --role lockbox.payloadViewer \ --subject serviceAccount:$WF_SA yc resource-manager folder add-access-binding \ --id $FOLDER_ID \ --role ai.languageModels.user \ --subject serviceAccount:$WF_SAWhere:
--id: Folder ID.--role: Role.--subject: Service account ID.
Result:
effective_deltas: - action: ADD access_binding: role_id: serverless.workflows.executor subject: id: ajeu2s3k358j******** type: serviceAccount ... effective_deltas: - action: ADD access_binding: role_id: ai.languageModels.user subject: id: ajersnus6rb2******** type: serviceAccount
Create service accounts:
-
sa-apigwwith theserverless.workflows.executorrole. -
sa-workflowswith the following roles:storage.uploaderstorage.viewerlockbox.payloadViewerai.languageModels.user
To create a service account, use the Create REST API method for the ServiceAccount resource or the ServiceAccountService/Create gRPC API call.
To assign a role to a service account, use the updateAccessBindings REST API method for the ServiceAccount resource or the ServiceAccountService/UpdateAccessBindings gRPC API call.
Set up a workflow
Set up a workflow to enable the bot to read and save the chat history, call the AI agent, and send responses to Telegram.
Tip
This guide describes how to create a workflow using the YaWL specification; however, you can also create and edit workflows using the constructor.

Prepare a YaWL specification
Save the workflow YaWL specification to a YAML file, e.g., yawl-spec.yaml.
yawl: '0.1'
start: do_work
steps:
do_work:
parallel:
branches:
# Branch which outputs _typing_ to reanimate the chat faster
send_typing_action:
start: send_typing_action
steps:
send_typing_action:
httpCall:
url: >-
https://api.telegram.org/bot\(lockboxPayload("<secret_ID>"; "token"))/sendChatAction
method: POST
headers:
Content-Type: application/json
body: |
\({
chat_id: .input.message.chat.id,
action: "typing"
})
# Basic logic
handle_update:
start: get_history
steps:
get_history:
objectStorage:
bucket: <bucket_name>
object: history/\(.input.message.chat.id).json
get:
contentType: JSON
output: '\({history: .Content})'
next: call_ai
catch:
- errorList:
- STEP_INVALID_ARGUMENT # There is no file or it is not JSON -> initialize
errorListMode: INCLUDE
output: '\({history: []})'
next: call_ai
call_ai:
aiAgent:
agentConfig:
role: You are a movie selection consultant
goal: >-
Help the user find a movie to watch based on their tastes.
When they send their first request, ask them to name some of their favorite movies
(one per line). Then use this information to make recommendations
and ask clarifying questions.
backstory: >-
History of previous conversations (JSON array of {role,message} objects):
"\(.history)"
model:
name: yandexgpt
tasks:
- description: \(.input.message.text)
result: Response in Markdown to send to Telegram.
output: '\({reply: .Result})'
next: send_reply
send_reply:
telegramBot:
token: \(lockboxPayload("<secret_ID>"; "token"))
sendMessage:
chatId: \(.input.message.chat.id)
text: \(.reply)
replyTo: \(.input.message.message_id)
parseMode: MARKDOWN
next: save_history
save_history:
objectStorage:
bucket: <bucket_name>
object: history/\(.input.message.chat.id).json
put:
contentType: JSON
content: >-
\(
.history +
[
{role:"user", message:.input.message.text},
{role:"assistant", message:.reply}
]
)
Where:
<bucket_name>: Name of the bucket you created earlier.<secret_ID>: ID of the secret you created earlier.
This example uses the YandexGPT Pro text model (name: yandexgpt). You can use another model available in synchronous mode in AI Studio.
Create a workflow
-
In the management console
, select Serverless Integrations. -
In the left-hand panel, click
Workflows. -
In the top-right corner, click Create workflow.
-
Choose the
YaML specificationmethod. -
In the code editor, paste the text of the previously prepared YaWL workflow specification.
-
Expand Additional parameters:
-
Enter a name for the workflow. Follow these naming requirements:
- It must be from 2 to 63 characters long.
- It can only contain lowercase Latin letters, numbers, and hyphens.
- It must start with a letter and cannot end with a hyphen.
-
Select the
sa-workflowsservice account. -
Under Logging, disable Write logs if you do not want to pay for storing logs.
-
-
Click Create.
-
See the description of the CLI command for creating a workflow:
yc serverless workflow create --help -
Create a workflow:
yc serverless workflow create \ --yaml-spec <specification_file> \ --name <workflow_name> \ --service-account-id $WF_SAWhere:
-
--yaml-spec: Path to the file with the workflow YaWL specification prepared earlier, e.g.,./yawl-spec.yaml. -
--name: Workflow name. Follow these naming requirements:- It must be from 2 to 63 characters long.
- It can only contain lowercase Latin letters, numbers, and hyphens.
- It must start with a letter and cannot end with a hyphen.
-
--service-account-id:sa-workflowsservice account ID.
Result:
id: dfqjl5hh5p90******** folder_id: b1g681qpemb4******** specification: spec_yaml: "yawl: ..." created_at: "2025-03-11T09:27:51.691990Z" name: my-workflow status: ACTIVE log_options: {} service_account_id: aje4tpd9coa******** -
To create a workflow, use the Create REST API method for the Workflows resource or the Workflow/Create gRPC API call.
Set up an API gateway
Set up an API gateway as a Telegram webhook.
Prepare an API specification
Save the OpenAPI 3.0api-spec.yaml:
openapi: 3.0.0
info:
title: Telegram Webhook → Workflows
version: 1.0.0
paths:
/handle:
post:
x-yc-apigateway-integration:
type: http
method: POST
service_account_id: <service_account_ID> # sa-apigw service account
url: https://serverless-workflows.api.cloud.yandex.net/workflows/v1/execution/start
requestBody:
description: Telegram update passthrough to Workflows
content:
application/json:
schema:
x-yc-schema-mapping:
type: static
template:
workflowId: <workflow_ID> # your workflow
input:
inputJson: ${.|tojson} # entire Telegram update as input
Where:
<service_account_ID>:sa-apigwservice account ID.<workflow_ID>: ID of the workflow created in the previous step.
Create an API gateway
-
In the management console
, select API Gateway. -
Click Create API gateway.
-
In the Name field, enter the name of the API gateway. Follow these naming requirements:
- It must be from 2 to 63 characters long.
- It can only contain lowercase Latin letters, numbers, and hyphens.
- It must start with a letter and cannot end with a hyphen.
-
Under Specification, paste the text of the OpenAPI specification you prepared earlier.
-
Under Logging, disable Write logs if you do not want to pay for storing logs.
-
Click Create.
-
Wait until the API gateway is created and select it.
-
Save the Default domain value, you will need it at the next step.
-
View the description of the CLI command for creating an API gateway:
yc serverless api-gateway create --help -
Create an API gateway:
yc serverless api-gateway create \ --name <API_gateway_name> \ --spec=<specification_file_path>Where:
-
--name: API gateway name. Follow these naming requirements:- It must be from 2 to 63 characters long.
- It can only contain lowercase Latin letters, numbers, and hyphens.
- It must start with a letter and cannot end with a hyphen.
-
--spec: Path to the specification file you created earlier.
Result:
id: d5d63uh1h26g******** folder_id: b1g681qpemb4******** created_at: "2025-06-14T10:23:19.682Z" name: ai-bot-gw status: ACTIVE domain: d5d63uh1h26g********.********.apigw.yandexcloud.net connectivity: {} log_options: folder_id: b1g681qpemb4******** execution_timeout: 300s -
-
Save the
domainvalue, you will need it at the next step.
To create an API gateway, use the Create REST API method for the ApiGateway resource or the ApiGatewayService/Create gRPC API call.
Set up a webhook for your bot
Run this command:
curl -s "https://api.telegram.org/bot<bot_token>/setWebhook" \
-d "url=<service_domain>/handle"
Where:
<bot_token>: Token you got when creating the bot.<service_domain>: Service domain of the API gateway you got when creating it.
Here is an example:
curl -s "https://api.telegram.org/bot1357246809:AAFhSteLniAw71g8jx6K5kTErO3********/setWebhook" \
-d "url=https://d5d0jdhgrro2********.********.apigw.yandexcloud.net/handle"
Result:
{"ok":true,"result":true,"description":"Webhook was set"}
Test your bot
-
Find the bot in Telegram by its username, which you created earlier.
-
Click START to start a chat.
-
Send the bot a list of movie titles, one per line.
Here is an example:
Movie 1 Movie 2 Movie 3Bot's response:
Hi there! Thank you for letting me know your preferences. Here are the movies I would recommend based on your tastes: ... Which of these films you would like to watch? Or do you have some other favourite movies you want me to consider?
What's next
Try customizing the YaWL workflow specification. For example, provide a different request to the text model:
...
call_ai:
aiAgent:
agentConfig:
role: You are a consultant which recommends music artists
goal: >-
Help the user find music to listen to based on their tastes.
When they send their first request, ask them to name some of their favorite
bands, artists, composers, and genres (one per line).
Then use this information to make recommendations and ask clarifying questions.
You can also add text or files as sources of information. Learn more in the AI Agent integration step description.
How to delete the resources you created
To stop paying for the resources you created: