Webhooks: Send Telegram Messages to Your CRM and Your Own Server
How to receive every post from Telegram channels on your own HTTP service via webhooks: the JSON format, media as links, and signature verification in Python.
Sometimes you need messages not in another channel but in your own system: a CRM, a knowledge base, analytics, your own bot. For this, pipelines have webhooks — HTTP requests to your URL for every delivered message.
Setup #
- In the Webhooks section, add your service’s URL, for example
https://crm.example.com/telegram. - In the pipeline editor, select this webhook.
- Copy the webhook’s secret — you’ll need it to verify the signature.
A pipeline can send messages only to a webhook, without any recipient channels.
What you receive #
For each message (an album comes as one request), you get a POST with JSON:
{
"pipeline_id": 12,
"account_id": 3,
"chat_id": -1001234567890,
"messages": [{
"id": 4521,
"date": 1791936000,
"text": "Today's news",
"entities": [{"type": "bold", "offset": 0, "length": 7}],
"media": {"type": "photo", "url": "https://cpo.st/m/…", "mime_type": "image/jpeg"}
}]
}
The text arrives after the pipeline’s filters and rewrites have been applied. Media is passed as links: the file is downloaded on first access and is available for 7 days.
Verifying the signature #
Every request is signed: the X-Copyposter-Signature header contains an HMAC-SHA256 of the string
<X-Copyposter-Timestamp>.<request body> using the webhook secret. Verification in Python:
import hmac, hashlib, time
def verify(secret: str, timestamp: str, body: bytes, signature: str) -> bool:
if abs(time.time() - int(timestamp)) > 300:
return False # old request — possibly a replay
expected = "sha256=" + hmac.new(secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Reliability #
If your service is unavailable or responds with 429/5xx, CopyPost retries the request after 1 s, 5 s,
30 s, 2 minutes and 10 minutes. Respond with 2xx quickly and do heavy processing in the background.
The URL must be public: webhooks are not sent to local or internal addresses.
Limits #
1,000 requests per month for free, then packs of 10,000 requests. Your current usage is shown on the Plan page.