Открытый API сделок и вебхуки CRM
Сделки Chato можно вести из своей программы: сайт создаёт сделку по заявке, 1С закрывает её после оплаты, склад ставит задачу менеджеру. Обратно Chato сообщает вашей программе, что произошло в CRM: сделку перенесли, выиграли, поменяли ответственного.
Настраивается в кабинете: Сделки → ⋯ → Настройки → API и вебхуки (видят администратор и владелец). Там же ссылка на справочник всех запросов — Swagger: https://chato.kz/api/v1/public/docs, описание в формате OpenAPI — https://chato.kz/api/v1/public/openapi.json.
Ключ API
Нажмите Новый ключ, дайте ему название («Сайт», «1С») и отметьте права:
| Право | Что разрешает |
|---|---|
deals:read |
читать сделки, их примечания |
deals:write |
создавать, менять, переносить, закрывать, удалять сделки, писать примечания |
contacts:read / contacts:write |
искать / создавать и менять контакты |
tasks:read / tasks:write |
читать / ставить и выполнять задачи |
pipelines:read |
воронки, этапы, доп. поля, причины отказа |
users:read |
список сотрудников (для responsibleUserId) |
messages:send |
писать клиентам |
Ключ показывается один раз — сразу скопируйте его. Chato хранит только его отпечаток и не сможет показать ключ снова. В списке видно, кто выпустил ключ и когда им пользовались в последний раз. Отозвать — ключ перестаёт работать сразу, программа получит 401.
Ключ — как пароль: храните его на сервере, в переменных окружения. Никогда не кладите его в код сайта, который видит браузер посетителя.
Всё, что программа делает по ключу, записывается в историю сделки от имени того, кто выпустил ключ, с пометкой «через API». Ключ не может больше, чем его автор: если сотруднику скрыта воронка, по его ключу она тоже скрыта. Автоматизации этапов, уведомления и живое обновление доски у коллег срабатывают так же, как при работе в кабинете.
Как отправлять запросы
https://chato.kz/api/v1/public
Authorization: Bearer chato_sk_...
Content-Type: application/json
Ключ можно передать и заголовком X-Api-Key. Успешный ответ всегда лежит в поле data.
- Лимит — 120 запросов в минуту на ключ. Сверх него —
429и заголовокRetry-After(через сколько секунд повторить). Остаток виден вX-RateLimit-Remaining. У каждого ключа свой счётчик: одна программа не съедает лимит другой. - Повтор без дублей — добавьте к
POSTзаголовокIdempotency-Key(любая строка до 255 символов, например id заявки у вас). Повтор с тем же ключом в течение суток вернёт первый ответ с заголовкомIdempotent-Replayed: trueи не создаст вторую сделку. Тот же ключ с другим телом —422 IDEMPOTENCY_KEY_REUSED.
Ошибки
Ошибка всегда одного вида:
{
"error": {
"code": "REQUIRED_FIELDS",
"message": "Заполните поля, чтобы перенести в «Договор подписан»",
"textCode": "REQUIRED_FIELDS",
"params": { "stage": "Договор подписан" },
"details": { "missing": [{ "key": "data_dogovora", "label": "Дата договора", "type": "DATE" }] }
},
"statusCode": 422
}
| Код | Когда |
|---|---|
401 UNAUTHORIZED |
нет ключа, ключ неверный или отозван |
403 FORBIDDEN_SCOPE |
у ключа нет нужного права |
404 DEAL_NOT_FOUND и т. п. |
нет такого объекта в вашей компании (чужие id всегда дают 404) |
400 VALIDATION_FAILED |
неверные данные, список — в details.validation |
422 REQUIRED_FIELDS |
для этапа нужны обязательные поля — какие, в details.missing |
422 LOSS_REASON_REQUIRED |
перенос в «Отказ» без причины, а воронка её требует |
429 RATE_LIMITED |
превышен лимит, смотрите Retry-After |
Справочники
curl https://chato.kz/api/v1/public/pipelines -H "Authorization: Bearer $CHATO_KEY"
Воронки с этапами (kind: OPEN — рабочий, WON — «Успешно», LOST — «Отказ»). Остальное:
GET /deal-fields— доп. поля:key(код поля — по нему пишутся значения), тип, варианты, на каких этапах обязательно;GET /loss-reasons— причины отказа;GET /users— сотрудники (id, имя, почта, роль).
Сделки
Создать
curl -X POST https://chato.kz/api/v1/public/deals \
-H "Authorization: Bearer $CHATO_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: site-order-10542' \
-d '{
"pipelineId": "PIPELINE_ID",
"title": "Заявка с сайта",
"amount": 150000,
"contact": { "name": "Айгерим", "phone": "+7 701 555 11 22", "email": "aigerim@example.com" },
"tags": ["сайт"],
"fields": { "gorod": "almaty", "obem": 40 }
}'
Контакт — contactId или contact. По contact Chato сначала ищет человека: по телефону (последние 10 цифр, формат любой), затем по e-mail (без учёта регистра); не нашёл — создаёт. В ответе contactCreated показывает, что произошло. Без pipelineId и stageId сделка встаёт в первый этап первой воронки. Ответственный по умолчанию — автор ключа; "responsibleUserId": null — без ответственного. Источник сделки — «API».
Доп. поля — объект fields по кодам из /deal-fields: для списка — id варианта, для множественного выбора — массив, для даты — 2026-09-28, для флажка — true/false. Неверное значение — 400 с названием поля.
Изменить
curl -X PATCH https://chato.kz/api/v1/public/deals/DEAL_ID \
-H "Authorization: Bearer $CHATO_KEY" -H 'Content-Type: application/json' \
-d '{"amount": 180000, "tags": ["сайт", "vip"], "fields": {"oplata": "invoice"}}'
Меняется только присланное. tags заменяют прежний список, null в поле очищает его.
Перенести, закрыть
# в этап — с теми же правилами, что на доске
curl -X POST https://chato.kz/api/v1/public/deals/DEAL_ID/move \
-H "Authorization: Bearer $CHATO_KEY" -H 'Content-Type: application/json' \
-d '{"stageId": "STAGE_ID", "fields": {"data_dogovora": "2026-09-28"}}'
# успешно
curl -X POST https://chato.kz/api/v1/public/deals/DEAL_ID/close \
-H "Authorization: Bearer $CHATO_KEY" -H 'Content-Type: application/json' \
-d '{"result": "won"}'
# отказом — с причиной из /loss-reasons
curl -X POST https://chato.kz/api/v1/public/deals/DEAL_ID/close \
-H "Authorization: Bearer $CHATO_KEY" -H 'Content-Type: application/json' \
-d '{"result": "lost", "lossReasonId": "REASON_ID", "lossComment": "выбрали другого"}'
Если у этапа есть обязательные поля, а в сделке они пустые, придёт 422 REQUIRED_FIELDS со списком полей — повторите запрос, добавив их в fields. close ищет первый этап «Успешно» / «Отказ» воронки сделки; нужен другой — передайте его stageId.
Найти, прочитать, удалить
curl 'https://chato.kz/api/v1/public/deals?pipelineId=PIPELINE_ID&status=open&limit=50' \
-H "Authorization: Bearer $CHATO_KEY"
Ответ: {"data": {"items": [...], "nextCursor": "..."}}. Следующая страница — тот же запрос с &cursor=<nextCursor>; nextCursor: null — страниц больше нет. Фильтры: pipelineId, stageId, status (open, won, lost, closed, unsorted), responsibleUserId (или none), contactId, tag, search (название, имя или номер клиента), updatedSince и createdSince (ISO-дата — удобно для синхронизации «что изменилось с прошлого раза»).
GET /deals/DEAL_ID— одна сделка;DELETE /deals/DEAL_ID— в корзину на 30 дней (204);POST /deals/DEAL_ID/restore— вернуть.
Примечания и задачи
curl -X POST https://chato.kz/api/v1/public/deals/DEAL_ID/notes \
-H "Authorization: Bearer $CHATO_KEY" -H 'Content-Type: application/json' \
-d '{"text": "Оплата прошла в 1С"}'
curl -X POST https://chato.kz/api/v1/public/deals/DEAL_ID/tasks \
-H "Authorization: Bearer $CHATO_KEY" -H 'Content-Type: application/json' \
-d '{"kind": "CALL", "text": "Перезвонить", "dueAt": "2026-10-01T09:00:00+05:00"}'
curl -X POST https://chato.kz/api/v1/public/tasks/TASK_ID/complete \
-H "Authorization: Bearer $CHATO_KEY" -H 'Content-Type: application/json' \
-d '{"result": "Дозвонились"}'
GET /deals/DEAL_ID/notes и GET /deals/DEAL_ID/tasks — списки. Виды задач: CALL (звонок), MEETING (встреча), WRITE (написать), OTHER и свои (CUSTOM + customTypeId).
Контакты
GET /contacts?phone=87015551122или?email=...— найти (до 20);POST /contacts{name, phone, email}— создать; если человек уже есть, вернётся он (200,"created": false), новый —201;PATCH /contacts/CONTACT_ID— поменять имя, телефон, e-mail.
Написать клиенту
С правом messages:send: POST /messages с conversationId или phone (для нового номера — ещё channelId), text и/или fileUrl — так же, как действие message входящей ссылки.
Вебхуки: события сделок на ваш адрес
Добавить адрес → впишите https-адрес и отметьте события. Сохраните — у адреса появится свой секрет подписи (кнопка «Показать»).
| Событие | Когда |
|---|---|
deal.created |
сделка создана (в кабинете, по API, из обращения) |
deal.updated |
поменялись название, сумма, теги, поля, ответственный |
deal.stage_changed |
сделка перешла в другой этап |
deal.won / deal.lost |
сделка закрыта успешно / отказом |
deal.deleted / deal.restored |
в корзину / из корзины |
deal.responsible_changed |
сменился ответственный |
task.created / task.completed |
задача поставлена / выполнена |
note.created |
добавлено примечание |
На тот же адрес можно получать и события чатов (message.received, conversation.closed и другие — см. Вебхуки).
Chato отправляет POST:
{
"id": "evt_3f2a9c...",
"event": "deal.won",
"createdAt": "2026-09-28T10:15:00.000Z",
"workspaceId": "cmr4sk0ya0001o701hl7ghbqk",
"data": {
"deal": {
"id": "cmulms3cp000r29eujik2dr1e",
"title": "Заявка с сайта",
"amount": 150000,
"currency": "KZT",
"status": "won",
"pipeline": { "id": "...", "name": "Продажи" },
"stage": { "id": "...", "name": "Успешно", "kind": "WON" },
"contact": { "id": "...", "name": "Айгерим", "phone": "77015551122", "email": "aigerim@example.com" },
"responsible": { "id": "...", "name": "Асхат", "email": "askhat@example.com" },
"tags": ["сайт"],
"fields": { "gorod": "almaty" },
"closedAt": "2026-09-28T10:15:00.000Z"
},
"changes": {
"stage": {
"from": { "id": "...", "name": "Счёт выставлен", "kind": "OPEN" },
"to": { "id": "...", "name": "Успешно", "kind": "WON" }
}
},
"actor": { "type": "api", "userId": "..." }
}
}
deal — снимок сделки в том же виде, что отдаёт API. changes — что поменялось (from → to; поля — как fields.<код>). actor.type: user (сотрудник в кабинете), api, webhook, automation, system. У task.* и note.created рядом с deal лежат task / note.
Заголовки: X-Chato-Event (событие), X-Chato-Event-Id (одинаков у повторов — по нему отбрасывайте дубли), X-Chato-Delivery, X-Chato-Timestamp, X-Chato-Signature.
Проверка подписи
X-Chato-Signature — это sha256= + HMAC-SHA256 секретом адреса от строки <X-Chato-Timestamp>.<сырое тело>. Считайте по сырому телу, до разбора JSON, и отбрасывайте запросы старше 5 минут.
Node.js (Express):
const crypto = require('node:crypto');
app.post('/chato', express.raw({ type: 'application/json' }), (req, res) => {
const ts = req.get('X-Chato-Timestamp');
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.CHATO_WEBHOOK_SECRET)
.update(`${ts}.${req.body}`)
.digest('hex');
const given = req.get('X-Chato-Signature') || '';
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
if (!fresh || given.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body);
res.sendStatus(200); // ответьте сразу, тяжёлую работу — в фон
});
PHP:
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_CHATO_TIMESTAMP'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $body, getenv('CHATO_WEBHOOK_SECRET'));
$given = $_SERVER['HTTP_X_CHATO_SIGNATURE'] ?? '';
if (abs(time() - (int) $ts) > 300 || !hash_equals($expected, $given)) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
http_response_code(200);
Python (Flask):
import hmac, hashlib, os, time
from flask import request, abort
@app.post("/chato")
def chato():
body = request.get_data() # сырые байты
ts = request.headers.get("X-Chato-Timestamp", "")
expected = "sha256=" + hmac.new(
os.environ["CHATO_WEBHOOK_SECRET"].encode(), f"{ts}.".encode() + body, hashlib.sha256
).hexdigest()
given = request.headers.get("X-Chato-Signature", "")
if abs(time.time() - int(ts or 0)) > 300 or not hmac.compare_digest(expected, given):
abort(401)
event = request.get_json()
return "", 200
Повторы, журнал, автоотключение
- Успех — любой ответ
2xxв течение 10 секунд. Иначе Chato повторит через 1 мин, 5 мин, 30 мин, 2 ч и 6 ч — всего шесть попыток. Перенаправления (3xx) не выполняются. - Журнал доставок под адресом: статус, код ответа, число попыток, что отправлено и что ответил ваш сервер. Отправить ещё раз — повторная доставка с тем же
idсобытия. Журнал хранится 30 дней. - Если доставки не проходят подряд много раз (25 попыток), адрес выключается сам, а владелец и администраторы получают уведомление. Почините приёмник и нажмите Включить.
- Проверить — отправляет тестовое событие
ping. Новый секрет — старый перестаёт подходить сразу.
Отвечайте 200 сразу, а обработку делайте в фоне: долгий ответ Chato посчитает неудачей и повторит — а повтор придёт с тем же X-Chato-Event-Id, по которому его легко узнать.
Сделки через входящую ссылку
Если вы уже пользуетесь входящей ссылкой ассистента, она умеет и сделки — те же правила, что у API, в истории пометка «через вебхук»:
{ "action": "deal.create", "contact": { "name": "Айгерим", "phone": "+77015551122" }, "deal": { "title": "Заказ из 1С", "amount": 77000 } }
{ "action": "deal.move", "dealId": "DEAL_ID", "stageId": "STAGE_ID" }
{ "action": "deal.note", "dealId": "DEAL_ID", "text": "Оплата прошла" }



