MAX channel statistics API: a step-by-step guide to API.Max
How to get MAX channel statistics through API.Max: a key, finding channels, statistics for 100 channels per request, posts, webhooks for new posts, MCP, saving requests, errors and choosing a plan — with Python samples.
API.Max is programmatic access to datool.ru data on channels in the MAX messenger: the channel catalog and cards, daily statistics and posts. With the API you can pull MAX channel statistics into your own spreadsheet, BI system, CRM, bot or AI assistant — no manual exports and no copying from the site. Responses come as JSON, each team member gets their own key, and you can start for free.
This article walks you from an empty key to a working integration: how to get a key, find a channel, fetch statistics for a hundred channels at once, export posts, receive new posts automatically through webhooks and avoid wasting requests. All samples are in Python with the requests library; the full method reference with curl samples is at docs.datool.ru/en/api/.
What you can get through API.Max
- The channel catalog — search by name, categories, territory, subscriber count, the A+ label, owner verification, government channels, the date of the last post and the quality index. The same filters as the catalog at max.datool.ru/en/channels/.
- A channel card — name, description, handle and link, subscribers, categories, territory, tags, the quality index and the citation index, the A+ label and the blue verification badge.
- Daily statistics — subscribers at the end of the day, number of posts, views and reactions of that day's posts, ad posts. Up to 100 channels in a single request.
- Posts — text, views, reactions by emoji, the ad flag, the repost source and attachments. In pages of up to 100 posts.
- New posts as events — a webhook delivers them to your server on its own.
- Directories of categories and territories — free.
What the API does not have and never will: private conversations, group chat messages and comments — we don't collect them. For private channels the API returns only the card.
Step 1. Get a key
Sign up at hi.datool.ru, open "API keys" and click "Create key". The full key, which looks like dtk_…, is shown only once — store it in your program's settings or in a password manager.
The key belongs to an organization: its plan, its request limit and the private channels it has verified. The limit is shared by the keys of all members. If a member is removed from the organization, their keys are revoked automatically.
When creating a key you can tick "Read and write". It is only needed to manage webhooks; a regular key is enough for reading data. The setting cannot be changed later, so it is convenient to create a separate key for webhooks.
Important
Don't publish the key in a repository or put it in your website's page scripts: anyone who has it can use up your organization's limit.
Step 2. Your first request: "Who am I"
The key goes in the Authorization: Bearer dtk_… header (or X-API-Key). A good first call is /v1/me/: it is free and shows your plan, limit and remaining requests.
import requests
API = "https://api.datool.ru/v1"
# key from your account — keep it in settings, not in code
HEADERS = {"Authorization": "Bearer dtk_your_key"}
me = requests.get(f"{API}/me/", headers=HEADERS, timeout=30).json()
# API plan, requests left and when the limit resets
print(me["api_tariff"], me["remaining_period"], me["period_end"])
If you get a response, the key works. A 401 error means the key is missing, wrong or revoked.
Step 3. Find channels
All other methods work with the channel's datool.ru ID — the id field. There are two ways to get it.
One channel by link. The resolve method understands a max.ru/… link, a @handle and a MAX chat ID:
channel = requests.get(
f"{API}/max/channels/resolve/",
params={"q": "https://max.ru/citynews"},
headers=HEADERS,
timeout=30,
).json()
print(channel["id"], channel["title"], channel["subscribers"])
A selection of channels by filters. For example, Moscow news channels with at least 10,000 subscribers that posted this week, sorted by quality index:
catalog = requests.get(
f"{API}/max/channels/",
params={
"category": "news", # category code from /max/categories/
"territory": "ru-mow", # territory code from /max/territories/
"subscribers_min": 10000,
"posted_within_days": 7,
"ordering": "-quality",
"limit": 100,
},
headers=HEADERS,
timeout=30,
).json()
ids = [card["id"] for card in catalog["results"]]
Take category and territory codes from the free /v1/max/categories/ and /v1/max/territories/ directories. A territory includes its descendants: a federal district code finds channels from all of its regions.
Step 4. Daily statistics for up to 100 channels per request
The /v1/max/stats/daily/ method returns "channel × day" rows: subscribers at the end of the day, number of posts, views and reactions of that day's posts and the number of ad posts. One request covers up to 100 channels and up to 366 days, with no more than 10,000 rows in total. It costs the same as a request for a single channel — 1 unit.
stats = requests.get(
f"{API}/max/stats/daily/",
params={
"channels": ",".join(map(str, ids)), # up to 100 comma-separated IDs
"from": "2026-10-01",
"to": "2026-10-25",
},
headers=HEADERS,
timeout=30,
).json()
for row in stats["results"]:
print(row["channel"], row["day"], row["subscribers"], row["views"], row["ad_posts"])
# IDs that don't exist or aren't visible to you
print(stats["not_found"])
Days follow Moscow time. If a channel was not polled on a given day, subscribers comes back as null — that means "no data", not zero, so don't treat such a day as a drop in audience. The free API.Max Test plan gives you the last 30 days; the full history starts with the Start plan.
Step 5. Channel posts
Posts come in pages, newest first. Take the link to the next page from the next field as is: the cursor in it remembers your filters and prevents duplicates, even if new posts appear in the channel while you are paging.
url = f"{API}/max/channels/@citynews/posts/"
params = {"from": "2026-10-01", "limit": 100}
posts = []
while url:
page = requests.get(url, params=params, headers=HEADERS, timeout=30).json()
posts += page["results"]
url, params = page["next"], None # next already contains all parameters
print(len(posts), "posts")
Each post has its text, publication time, views, reactions by emoji ({"👍": 180, "🔥": 56}), the is_ad flag, the repost source and attachments. The is_ad=true filter returns only ad posts, which is handy for advertiser analysis. Posts are available from the API.Max Start plan.
Step 6. New posts without polling: webhooks
Polling a feed every five minutes is expensive and slow. A webhook sends a POST request to your server about every new post in the selected channels, usually 1–2 minutes after we read it. Webhooks are available from the API.Max Growth plan (1 webhook for up to 500 channels); Profi gets 5 webhooks for up to 5,000 channels each. Managing webhooks does not use requests.
A webhook is created with a "Read and write" key belonging to the organization's owner or an administrator:
hook = requests.post(
f"{API}/max/webhooks/",
json={"url": "https://example.com/hooks/datool", "channels": ids[:500]},
headers=HEADERS,
timeout=30,
).json()
# the signing secret is shown only once — save it
print(hook["id"], hook["secret"])
Three rules for a reliable receiver:
- Verify the signature. Every event is signed: the
X-Datool-Signatureheader contains a timestamp and an HMAC-SHA256. Check the signature before parsing JSON and reject events older than 5 minutes. A ready-made verification function and a Flask receiver are in the Webhooks article. - Respond quickly. Return a 2xx code within 10 seconds and do heavy processing after the response. Otherwise we retry the delivery after 1, 5 and 15 minutes, then 1, 3, 6 and 12 hours.
- Be ready for duplicates. The same event may arrive twice — match posts by
id.
If no delivery succeeds within a day, the webhook is switched off and the owners and administrators get an email. Fix your server and switch the webhook back on with the button on the "API keys" page or with a PATCH request containing {"is_active": true}.
MAX data in an AI assistant: MCP
If you'd rather not write code, connect the MCP server https://api.datool.ru/v1/mcp/ to your assistant with the same key. Claude, Cursor and other MCP clients will find the channel, look at its statistics and posts and answer a question like "how did @citynews grow in October". Each tool call costs the same as the corresponding API method. Setup for different clients is described in MCP for AI assistants and on hi.datool.ru/en/mcp/.
How not to waste requests
A request costs 1 unit no matter how many rows it returns. That leads to a few simple rules:
- Fetch in batches. Statistics for 100 channels is 1 request, not 100. Get cards for a list of channels through the catalog with
ids(up to 100 IDs) instead of one by one. - Use pages of 100. Set
limit=100for the catalog and posts: you get half as many pages as with the default. - Don't poll the feed — use a webhook. New posts arrive on their own, and you no longer need requests to check the feed.
- Cache directories and channel IDs. A channel's datool.ru ID does not change — look it up once with
resolveand store it. - Watch the headers.
X-Quota-Remainingis what is left for the period,X-Quota-Resetis when a new period begins,X-RateLimit-Remainingis what is left for the current second.
Requests without a key or with a wrong key, requests rejected by the limit (429) and requests that failed on our side (500, 503) do not count against the limit.
Errors: how to write a reliable client
An error looks like {"detail": "text", "code": "code"}. Base decisions in your program on code and show the text to people — with the Accept-Language: en header it comes in English.
- 429 —
rate_limited(too often) orquota_exceeded(no requests left for the period). Wait as many seconds as theRetry-Afterheader says. - 503 —
timeout(the selection is too large: narrow the period or the number of channels) orunavailable(the database is temporarily unavailable: retry in a few minutes). Such requests don't use the limit. - 403 —
tariff_required(the method or period is closed by your plan),closed_channel(posts of private channels are not returned),read_only_key(the key has no write permission). - 404 — the channel or post doesn't exist, or your key can't see it.
The full list of codes is in the Errors article.
Which plan to choose
- API.Max Test — free. 1,000 requests per 30 days, 1 request per second, cards and statistics for the last 30 days. To try things out and test an idea.
- API.Max Start — 2,990 rubles a month. 100,000 requests, 5 per second, 2 keys, the full statistics history and posts. For your own services, bots and regular reports.
- API.Max Growth — 9,990 rubles a month. 300,000 requests, 10 per second, 5 keys and webhooks. For analytics products that need new posts right away.
- API.Max Profi — 29,990 rubles a month. 1.5 million requests, 20 per second, 20 keys and the right to show the data to your clients. For agencies and platforms.
- API.Max Corporate — by contract. From 5 million requests and a database export.
The Business subscription already includes 10,000 requests a month. A limit month is 30 days from payment; if you run out earlier, you can buy a pack of 100,000 requests for 990 rubles. All plans are on max.datool.ru/en/api/.
Frequently asked questions
Can I get statistics for any MAX channel through the API?
For any public channel in the datool.ru catalog: its card, daily statistics and posts. For a private channel the API returns only the card. If the channel you need is not in the catalog yet, you can add it at max.datool.ru/en/channels/add/.
How often is the data in the API updated?
The same as on the site: the API returns the same data you see on channel pages. How often channels of different sizes are polled is described in the documentation article "Where the data comes from and how often it is updated".
How much does it cost to export a channel's entire post history?
One request per 100 posts. A channel with 5,000 posts takes 50 requests. On the Start plan with 100,000 requests a month, that is a drop in the ocean.
Can I show API data to my clients?
Yes, from the API.Max Profi plan, which includes the right to show the data to clients. On other plans the data is for your own work.
Is there a ready-made library for the API?
There is no separate library, but there is an OpenAPI schema at https://api.datool.ru/v1/schema/?lang=en. A generator can build a client in any language from it, and Postman can import all methods. You can try requests without code in Swagger — the link is on the method reference page.
API.Max is open: create a free key in your account and start with the Quick start — your first request takes a couple of minutes.




