API Reference
Base URL: https://wocrm.ru/api/v1 · Версия: v1
Аутентификация #
Все запросы к API требуют заголовок Authorization с Bearer-токеном организации. Ключи создаются в настройках организации и привязаны к ней (не к пользователю).
Authorization: Bearer wocrm_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
| Поле | Значение |
|---|---|
| Схема | Bearer |
| Заголовок | Authorization |
| Формат | wocrm_live_ + 40 случайных символов |
| Хранение | SHA-256 хеш на сервере |
| Отзыв | Немедленный — через настройки организации |
Идемпотентность #
Передайте заголовок Idempotency-Key для защиты от дублей при повторных запросах (сетевой таймаут, retry в очереди).
Idempotency-Key: site-form-{{userId}}-{{timestamp}}
| Правило | Значение |
|---|---|
| Максимальная длина | 255 символов |
| Область видимости | Организация — ключи уникальны в рамках одной организации |
| Время хранения | 72 часа с момента первого запроса |
| При повторе | HTTP 200 + "idempotent_replay": true |
Списки и пагинация #
Коллекции возвращаются постранично. Все GET-эндпоинты списков отдают единый конверт { ok, data, meta }.
GET-эндпоинты
| Метод | Путь | Описание |
|---|---|---|
| GET | /api/v1/leads | Лиды. Фильтры: status, assigned_to, search |
| GET | /api/v1/leads/{id} | Один лид |
| GET | /api/v1/contacts | Контакты. Фильтр: search |
| GET | /api/v1/contacts/{id} | Один контакт |
| GET | /api/v1/deals | Сделки. Фильтры: status, assigned_to |
| GET | /api/v1/deals/{id} | Одна сделка |
| GET | /api/v1/appointments | Онлайн-записи. Фильтры: status, from, to |
| GET | /api/v1/appointments/{id} | Одна запись |
Параметры пагинации
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
per_page | integer | 25 | Размер страницы, максимум 100 |
page | integer | 1 | Номер страницы |
Пример ответа
{
"ok": true,
"data": [ { "id": 12, "name": "Иван", "status": "new" } ],
"meta": { "total": 240, "per_page": 25, "current_page": 1, "last_page": 10 }
}
search (по слепому индексу), а не по подстроке.POST /api/v1/leads #
/api/v1/leads/{id} (изменение — поля как ниже, все необязательны) и DELETE /api/v1/leads/{id} (удаление).Создаёт входящий лид в организации. Если указан Idempotency-Key и лид с таким ключом уже существует — возвращает его без создания дубля.
Заголовки
| Заголовок | Обяз. | Описание |
|---|---|---|
Authorization | да | Bearer {token} |
Content-Type | да | application/json |
Idempotency-Key | нет | Ключ для защиты от дублей (≤ 255 символов) |
Поля тела (JSON)
| Поле | Тип | Обяз. | Макс. | Описание |
|---|---|---|---|---|
name | string | да | 255 | Имя лида |
phone | string | нет | 64 | Телефон |
email | string | нет | 255 | |
message | string | нет | 8192 | Сообщение / комментарий |
source | string | нет | 64 | Источник (landing, vk, site и т.д.) |
Пример запроса
curl -X POST https://wocrm.ru/api/v1/leads \
-H "Authorization: Bearer wocrm_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-form-1234567890" \
-d '{
"name": "Иван Петров",
"phone": "+7 999 123-45-67",
"email": "ivan@example.com",
"source": "landing_page",
"message": "Хочу записаться на консультацию"
}'
Ответы
| Код | Ситуация | Тело ответа |
|---|---|---|
| 201 | Лид создан | {"ok":true,"lead_id":1042} |
| 200 | Идемпотентный повтор | {"ok":true,"lead_id":1042,"idempotent_replay":true} |
| 422 | Ошибка валидации | {"ok":false,"error":"validation_failed","errors":{...}} |
| 422 | Квота лидов исчерпана | {"ok":false,"error":"lead_quota_exceeded","message":"..."} |
| 401 | Неверный токен | {"ok":false,"error":"unauthorized"} |
Онлайн-записи (appointments) #
Создание и чтение записей на встречу/услугу — для внешних систем бронирования и виджетов.
GET /api/v1/appointments
Список записей. Фильтры: status, from (дата с), to (дата по), пагинация per_page.
curl "https://wocrm.ru/api/v1/appointments?from=2026-07-01&per_page=50" \
-H "Authorization: Bearer <org_api_key>"
POST /api/v1/appointments
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
client_name | string | да | Имя клиента |
scheduled_at | datetime | да | Дата и время (ISO 8601) |
client_phone | string | нет | Телефон |
client_email | string | нет | |
duration_minutes | integer | нет | Длительность, мин (по умолчанию 30) |
type | string | нет | Тип записи |
status | string | нет | Статус (по умолчанию scheduled) |
notes | string | нет | Заметки |
deal_id | integer | нет | Привязка к сделке (в вашей организации) |
curl -X POST https://wocrm.ru/api/v1/appointments \
-H "Authorization: Bearer <org_api_key>" \
-H "Content-Type: application/json" \
-d '{"client_name":"Иван","scheduled_at":"2026-07-15T14:00:00","duration_minutes":60}'
Ответ 201: { "ok": true, "data": { "id": 88, ... } }
Contacts — создание, изменение, удаление #
POST /api/v1/contacts PATCH /api/v1/contacts/{id} DELETE /api/v1/contacts/{id}
| Поле | Тип | Обяз. (POST) | Описание |
|---|---|---|---|
name | string | да | Имя (до 255) |
phone | string | нет | Телефон (до 64) |
email | string | нет | |
company | string | нет | Компания |
position | string | нет | Должность |
city | string | нет | Город |
notes | string | нет | Заметки |
При PATCH любое поле необязательно (обновляются только переданные). DELETE удаляет контакт организации.
curl -X POST https://wocrm.ru/api/v1/contacts \
-H "Authorization: Bearer <org_api_key>" -H "Content-Type: application/json" \
-d '{"name":"Иван Петров","phone":"+79990001122","email":"ivan@mail.ru"}'
Deals — создание и изменение #
POST /api/v1/deals PATCH /api/v1/deals/{id}
| Поле | Тип | Обяз. (POST) | Описание |
|---|---|---|---|
title | string | да | Название сделки |
amount | number | нет | Сумма (≥ 0) |
status | string | нет | Одно из: open, won, lost |
priority | string | нет | Одно из: low, medium, high |
lead_id | integer | нет | Привязка к лиду (только POST) |
notes | string | нет | Заметки |
При PATCH все поля необязательны. Удаление сделок через API не предусмотрено.
GET /api/v1/openapi.yaml #
Возвращает машиночитаемую спецификацию OpenAPI 3.0 (YAML) по всем эндпоинтам v1: leads, contacts, deals, appointments — со схемами, параметрами и кодами ответов. Не требует авторизации.
curl https://wocrm.ru/api/v1/openapi.yaml
Импорт в Postman / генерация SDK #
Postman — популярный бесплатный инструмент для работы с API. По нашей OpenAPI-спеке он за минуту создаёт готовую коллекцию всех запросов.
Импорт коллекции в Postman
- Откройте Postman → Import → вкладка Link.
- Вставьте ссылку на спеку и нажмите Continue → Import:
https://wocrm.ru/api/v1/openapi.yaml
- В настройках коллекции → Authorization → тип Bearer Token → вставьте ключ организации из настроек API.
- Готово — можно отправлять запросы к leads, contacts, deals, appointments.
openapi-generator или swagger-codegen с этим же файлом.Быстрый старт через curl
# список лидов
curl "https://wocrm.ru/api/v1/leads?per_page=10" \
-H "Authorization: Bearer <ваш_ключ>"
Коды ошибок #
| HTTP | error | Причина |
|---|---|---|
| 400 | invalid_json | Тело запроса не является валидным JSON |
| 401 | unauthorized | Токен отсутствует, неверен или отозван |
| 403 | forbidden | Нет прав для данной операции |
| 404 | not_found | Ресурс не существует |
| 422 | validation_failed | Не переданы обязательные поля или нарушены ограничения |
| 422 | lead_quota_exceeded | Достигнут лимит лидов по тарифу |
| 422 | invalid_idempotency_key | Idempotency-Key длиннее 255 символов |
| 429 | too_many_requests | Превышен rate limit — ожидайте Retry-After секунд |
| 500 | server_error | Внутренняя ошибка — обратитесь в поддержку |
Rate limits #
Формат webhook-запроса #
WOCRM отправляет POST на ваш URL с JSON-телом:
{
"event": "lead.created",
"sent_at": "2026-01-01T12:00:00+00:00",
"organization_id": 7,
"data": { ... } // зависит от события
}
Заголовки webhook #
| Заголовок | Пример | Описание |
|---|---|---|
Content-Type | application/json | Тело всегда JSON |
X-Wocrm-Event | lead.created | Тип события |
X-Wocrm-Signature | sha256=abc123… | HMAC-SHA256 тела запроса |
X-Wocrm-Delivery | uuid-v4 | Уникальный ID доставки |
User-Agent | WOCRM-Webhook/1.0 | Идентификатор отправителя |
Проверка подписи #
Заголовок X-Wocrm-Signature: sha256=<hex> содержит HMAC-SHA256 от сырого тела запроса, подписанный секретом webhook-эндпоинта.
hash_equals).PHP (Laravel)
$secret = config('services.wocrm_webhook_secret');
$payload = $request->getContent(); // raw body — до json_decode
$sig = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (! hash_equals($sig, $request->header('X-Wocrm-Signature', ''))) {
abort(401, 'Invalid signature');
}
Node.js (Express)
const crypto = require('crypto');
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = 'sha256=' + crypto
.createHmac('sha256', process.env.WOCRM_SECRET)
.update(req.body) // Buffer — raw body
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(req.headers['x-wocrm-signature'] || ''))) {
return res.sendStatus(401);
}
// ...
});
Python (Flask)
import hmac, hashlib
@app.route('/webhook', methods=['POST'])
def webhook():
secret = os.environ['WOCRM_SECRET'].encode()
sig = 'sha256=' + hmac.new(secret, request.data, hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, request.headers.get('X-Wocrm-Signature', '')):
abort(401)
# ...
Retry-политика #
При неуспешной доставке (не 2xx, или таймаут 30 сек) WOCRM повторяет по расписанию:
| Попытка | Задержка |
|---|---|
| 1-я (первичная) | немедленно |
| 2-я | +10 сек |
| 3-я | +60 сек |
| 4-я | +5 мин |
| 5-я (последняя) | +30 мин |
События: lead.* #
lead.created — новый лид
// data:
{
"lead_id": 1042,
"lead": {
"id": 1042, "name": "Иван Петров", "email": "ivan@example.com",
"phone": "+7 999 123-45-67", "status": "new", "priority": null,
"assigned_to": null, "source_id": null,
"last_channel": "api", "created_at": "2026-01-01T12:00:00+00:00"
}
}
lead.status_changed
// data:
{
"lead_id": 1042,
"old_status": "new",
"new_status": "in_progress",
"lead": { /* объект лида */ }
}
Статусы: new · in_progress · converted · lost · closed
lead.assigned
// data:
{
"lead_id": 1042,
"assigned_to": 5, // ID пользователя или null
"lead": { /* объект лида */ }
}
lead.idle — лид не обрабатывается 30+ дней
// data:
{
"lead_id": 1042
}
// Срабатывает 1 раз в сутки по расписанию (cron)
События: deal.* #
deal.created
// data:
{
"deal_id": 10,
"deal": {
"id": 10, "title": "Проект X", "amount": 150000.00,
"status": "open", "funnel_id": 1, "funnel_stage_id": 3,
"contact_id": 7, "lead_id": 1042, "assigned_to": 5,
"created_at": "2026-01-01T12:00:00+00:00"
}
}
deal.stage_changed
// data:
{
"deal_id": 10,
"lead_id": 1042,
"funnel_stage_id": 4,
"previous_funnel_stage_id": 3
}
deal.won
// data:
{ "deal_id": 10, "lead_id": 1042, "contact_id": 7, "amount": 150000.00 }
deal.lost
// data:
{ "deal_id": 10, "lead_id": 1042, "contact_id": 7 }
События: message.* #
message.received / message.sent
// data (поля зависят от канала):
{
"lead_id": 1042,
"channel": "telegram", // telegram | vk | whatsapp | api | ...
"direction": "in", // in | out
"text": "Здравствуйте!",
"message_id": "tg_123456789"
}
События: contact.* #
contact.created
// data:
{ "contact_id": 7, "lead_id": 1042 }
contact.churn_risk — риск оттока
// data:
{
"contact_id": 7,
"health_score": 28 // <= 35 — риск оттока
}
// Срабатывает не чаще 1 раза в 7 дней на контакт
События: invoice.* #
invoice.status_changed
// data:
{
"invoice_id": 55,
"lead_id": 1042,
"old_status": "pending",
"new_status": "paid"
}