TL;DR
This guide walks you through building a Telegram to CRM pipeline with OpenClaw. You will create a bot, secure the webhook with a secret header, map message fields to contact properties, and push new records into your CRM with retry logic and audits. The result is a reliable chat based intake that supports consent capture, enrichment, and monitoring. It is designed for teams that want fast setup without sacrificing security or data quality for lead generation. You will finish with a simple monitoring checklist.
What you will build
You will set up a Telegram bot that collects contact details through a structured chat flow and posts them to a CRM as new contacts. The OpenClaw playbook will accept Telegram webhook events, validate authenticity, transform input to a clean schema, upsert into HubSpot, and store a consent trail. The approach works with other CRMs too, because the HTTP request step abstracts the destination.
Why Telegram for intake
Telegram delivers a low friction chat surface that can capture interest the moment it appears. For marketing teams this is useful when a visitor discovers your community channel or a campaign drives traffic to a bot. With a webhook you can process messages in real time and route qualified conversations to sales, support, or automation.
For a deeper look at what the product can automate, see the overview of AI marketing automation features. If you are new to the platform, start with ButterGrow to understand how the hosted OpenClaw assistant works for go to market teams.
Architecture at a glance
- Telegram bot receives a message such as "/start" or a command like "/lead".
- Telegram sends an HTTPS POST to your OpenClaw webhook with a secret token header.
- OpenClaw validates the secret, normalizes the payload, and runs policy checks.
- A transform maps chat fields to CRM properties and builds an idempotency key.
- An HTTP request upserts the contact and logs consent and attribution.
Here is a quick comparison of ways to receive updates from Telegram.
| Approach | Latency | Reliability considerations | Operational notes |
|---|---|---|---|
| Webhook to OpenClaw | Low | Requires HTTPS and header validation | Best for production and observability |
| Long polling | Medium | Process restarts drop in flight updates | Acceptable for prototypes only |
| Third party middleware | Variable | Adds another failure point and cost | Useful when your CRM is not directly reachable |
This tutorial is the practical answer to how to connect a Telegram bot to HubSpot using OpenClaw. If you came looking for a Telegram webhook to CRM tutorial, you can follow the steps below and adapt the destination to any system with an HTTP API.
Prerequisites
- A Telegram account and a bot created via BotFather.
- A stable HTTPS domain for your webhook endpoint.
- An OpenClaw workspace with permission to create playbooks and secrets.
- A HubSpot account with a Private App token that can create contacts.
Step by step build
Step 1Create a Telegram bot and note the token
- In Telegram, start a chat with BotFather and run
/newbotto name your bot and receive the token. 2) Keep the token secure. You will store it as an OpenClaw secret. 3) Decide which commands you want to support. For this tutorial we will accept/startfor a welcome flow and/leadto collect contact details.
Step 2Set the webhook with a secret token
Telegram supports a secret header on every webhook delivery. Generate a 32 character random value and pass it as secret_token when calling setWebhook. Telegram will include X-Telegram-Bot-Api-Secret-Token in each request. Your webhook must reject requests with a missing or mismatched header.
Use this call to set the webhook.
curl -X POST "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.yourdomain.com/hooks/telegram/<bot_username>",
"secret_token": "<A_32_CHAR_RANDOM_VALUE>",
"allowed_updates": ["message"]
}'
For API details, see the official Telegram Bot API documentation and the setWebhook method reference.
Step 3Create secrets in OpenClaw
Add two secrets to your workspace.
TELEGRAM_SECRET_TOKENequals the 32 character value you set above.HUBSPOT_PRIVATE_APP_TOKENequals your HubSpot Private App token.
You will reference both in the playbook with secrets.<NAME>.
Step 4Scaffold the OpenClaw playbook
Create a new playbook and add a webhook trigger that accepts Telegram events. The snippet below shows a minimal version you can paste into a new playbook. Adjust names to match your workspace conventions.
name: telegram-to-crm-intake
version: 1
triggers:
- id: tg_webhook
type: http_webhook
config:
method: POST
path: /hooks/telegram/:bot
auth: none
rate_limit_per_minute: 600
validation:
headers:
- name: X-Telegram-Bot-Api-Secret-Token
operator: equals
value: ${secrets.TELEGRAM_SECRET_TOKEN}
schema:
type: object
required: [message]
properties:
update_id: { type: integer }
message:
type: object
required: [chat, text, date]
properties:
message_id: { type: integer }
date: { type: integer }
text: { type: string }
chat:
type: object
required: [id, type]
properties:
id: { type: integer }
type: { type: string }
username: { type: string }
first_name: { type: string }
last_name: { type: string }
steps:
- id: parse
type: transform
with:
code: |
const m = input.message || {};
const text = (m.text || "").trim();
const parts = text.split(/\s+/);
const cmd = parts[0];
const args = Object.fromEntries(parts.slice(1).map(p => {
const [k, v] = p.split(":");
return [k?.toLowerCase(), v];
}));
const email = args.email || "";
const phone = args.phone || "";
const source = args.source || "telegram";
const chat = m.chat || {};
const idempotency = `${chat.id}:${email || phone}`;
return {
cmd,
email,
phone,
source,
chat_id: chat.id,
username: chat.username,
first_name: chat.first_name,
last_name: chat.last_name,
idempotency
};
- id: guard
type: policy
with:
rules:
- if: "!output.parse.email && !output.parse.phone"
then: "deny"
reason: "missing contact handle"
- if: "output.parse.cmd !== '/lead' && output.parse.cmd !== '/start'"
then: "deny"
reason: "unsupported command"
- id: create_contact
type: http_request
with:
url: https://api.hubapi.com/crm/v3/objects/contacts
method: POST
headers:
Authorization: "Bearer ${secrets.HUBSPOT_PRIVATE_APP_TOKEN}"
Content-Type: application/json
Accept: application/json
Idempotency-Key: "${output.parse.idempotency}"
body:
properties:
email: "${output.parse.email}"
phone: "${output.parse.phone}"
firstname: "${output.parse.first_name}"
lastname: "${output.parse.last_name}"
hs_utm_source: "${output.parse.source}"
tg_username: "${output.parse.username}"
- id: consent_log
type: data_log
with:
table: consent_events
record:
subject: "telegram:${output.parse.chat_id}"
event: "opt_in"
policy_version: "v1"
timestamp: "${now()}"
on_error:
- id: retry
type: retry
with:
for: [create_contact]
strategy: exponential
max_attempts: 5
min_backoff_ms: 500
This playbook exposes an HTTPS endpoint, validates the Telegram secret header, parses a simple command format, and upserts a contact in HubSpot. The Idempotency-Key header ensures repeated deliveries do not create duplicates.
Step 5Map fields and normalize input
You can guide users to provide contact details in a single message. A typical format is /lead email:ana@example.com phone:+14155550123 source:community. You can also switch the flow to a multistep chat and store intermediate state in OpenClaw if your use case needs progressive profiling.
If you need to add more properties, extend the transform and the request body. Keep field names consistent and convert phone numbers to E.164 format to reduce downstream errors.
Step 6Verify the secret header in code
If you prefer to add a code based check, you can verify the header in a custom step or an edge function. Here is a simple Node.js example that rejects requests that do not present the expected secret.
export default async function handler(req, res) {
const expected = process.env.TELEGRAM_SECRET_TOKEN;
const got = req.headers["x-telegram-bot-api-secret-token"] || "";
if (!expected || got !== expected) {
return res.status(401).json({ ok: false, error: "unauthorized" });
}
// continue processing
res.status(204).end();
}
This endpoint logic mirrors the declarative header validation in the playbook. Use one path or the other to avoid double handling.
Step 7Create a HubSpot contact manually to test
Before wiring the transform to the live request, confirm your token works by creating a test contact with curl.
curl -X POST 'https://api.hubapi.com/crm/v3/objects/contacts' \
-H 'Authorization: Bearer <HUBSPOT_PRIVATE_APP_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"properties": {
"email": "ana+test@example.com",
"firstname": "Ana",
"lastname": "Lead",
"phone": "+14155550123",
"hs_utm_source": "telegram"
}
}'
If you receive HTTP 201 your token and scope are valid. If you see HTTP 401 or 403, double check scopes and rotate the token if needed.
Step 8Test the end to end flow
Send a message to your bot like this.
/lead email:ana@example.com phone:+14155550123 source:community
Inspect the OpenClaw run. The transform step should extract fields, the policy step should allow the command, and the HTTP request should return HTTP 201 or 204. In the CRM, verify that properties are populated, including the username if available.
Step 9Add consent capture and routing
Even if you already record an opt in event, you often need a stronger trail. Add a prompt that asks the user to confirm marketing consent explicitly. Create a second data log step for consent updates and store the policy version and timestamp. Later, you can gate outbound campaigns on the latest event per subject.
For routing, consider adding a branch that sends a notification to Slack or email when the message contains target keywords. You can also use CRM workflows to assign owners based on region or product interest.
Step 10Harden for production
- Enforce HTTPS and prefer a stable domain for the webhook URL.
- Restrict allowed updates to only the message types you process.
- Add IP allow listing if your edge supports it and document the ranges.
- Turn on alerting and a dead letter queue for failed deliveries.
- Track success, failure, and retry counts with a dashboard or logs.
Troubleshooting and common pitfalls
- Webhook not firing. Verify that setWebhook returns ok true and that your endpoint returns HTTP 200 on a simple health check. Inspect OpenClaw logs for header validation failures.
- Duplicate contacts. Ensure the idempotency key is stable and unique. Upsert on email in the CRM and handle retry side effects.
- Missing properties. Confirm that your transform returns the expected fields and that property names match the CRM schema exactly.
- Timeouts. Keep processing inside the webhook fast and move slow work to background jobs when needed.
Next steps
If you plan to automate downstream messaging, read our WhatsApp drip campaigns tutorial on OpenClaw for ideas on nurture flows and audience selection. For a broader view of the platform, browse AI marketing automation features and then explore more from the ButterGrow blog to see what other teams have shipped.
To follow this guide in your workspace, you can get started in minutes. The onboarding flow creates a sample project and shows how to set it up with a secure webhook and a first destination.
Building this with the hosted assistant keeps you focused on outcomes while we run the infrastructure. If you want hands on help, the answers to common questions in the FAQ are a good place to start.
References
- Telegram Bot API documentation - Official reference for all Telegram bot methods and objects
- setWebhook method reference - Parameters for configuring a webhook with a secret token
- HubSpot Contacts API - Create and update contact objects with a Private App token
Frequently Asked Questions
How do I verify Telegram webhook requests in OpenClaw?+
Set a secret_token when calling Telegram setWebhook and validate the X-Telegram-Bot-Api-Secret-Token header in your webhook step. Reject any request without an exact match and log the failure.
Which HubSpot permissions are required to create contacts from bot messages?+
Use a Private App token with crm.objects.contacts.write and crm.objects.contacts.read. Store the token in OpenClaw secrets, reference it from the HTTP request step, and never hardcode credentials in playbooks.
Can I capture UTM parameters or campaign codes in this flow?+
Yes. Extend the bot command to accept key value pairs or prompt the user for source and campaign, then map those fields to HubSpot properties like hs_utm_source and hs_utm_campaign in the transform step.
How do I prevent duplicate contacts when a user sends multiple messages?+
Create an idempotency key using the Telegram chat id and a normalized email or phone if present. In HubSpot requests, upsert on the email property and handle HTTP 409 or 204 responses gracefully to avoid duplicates.
What is the recommended approach for consent and opt out in Telegram?+
Treat consent as an event stream. Record explicit opt in and opt out events with timestamps and the policy version, store them in a durable log, and gate any outbound messaging on the latest consent state for that chat id.
How can I test this end to end without a public URL?+
Use a secure tunnel such as an HTTPS forwarding service to expose your local OpenClaw webhook endpoint. Point Telegram setWebhook at the tunnel URL during development and switch to a stable domain before launch.
Ready to try ButterGrow?
See how ButterGrow can supercharge your growth with a quick demo.
Book a Demo