ТапВей API

API проекта ТапВей: онлайн-запись, магазин, заявки, CRM, статистика. Доступно на тарифах «Про» и «Бизнес». Адрес: https://api.tapway.me/v1. Машинное описание: openapi.json (OpenAPI 3.1) — его можно открыть в Postman, Insomnia или сгенерировать клиент.

Ключ работает только с вашего сервера: запросы из браузера посетителя не поддерживаются, и ключ нельзя показывать на страницах сайта.

Ключ и права

Ключ создаёт владелец проекта в кабинете: Настройки → API, с подтверждением пароля. Ключ показывается один раз — сохраните его. Передавайте в заголовке:

curl https://api.tapway.me/v1/me \
  -H "Authorization: Bearer tw_live_…"

У ключа есть права — включаются галочками при создании:

ПравоЧто даёт
bookings:readОнлайн-запись: чтение
bookings:writeОнлайн-запись: создание и изменение
leads:readЗаявки и ответы квизов: чтение
shop:readМагазин: чтение
shop:writeМагазин: товары и заказы
crm:readCRM: чтение контактов
crm:writeCRM: контакты и сделки
stats:readСтатистика: чтение

Ключ отзывается в кабинете и автоматически — при передаче проекта другому владельцу. Тариф ниже «Про» — ответ 402, ключи заработают снова после продления.

Лимиты

ТарифВ минутуВ сутки
Про6010 000
Бизнес300100 000

Остаток — в заголовках X-RateLimit-Remaining-Minute и X-RateLimit-Remaining-Day. Сверх лимита — 429 и Retry-After. Отдельно: фото — 300 в час, пакетная загрузка товаров — 60 пакетов в час.

Ответы и ошибки

Успех — {"data": …}. Ошибка — HTTP-код и тело:

{
  "error": {
    "code": "slot_unavailable",
    "message": "Выбранное время недоступно"
  }
}
КодКогда
400 invalidНеверные поля; в error.fields — какие
401 unauthorizedНет ключа, ключ неверный или отозван
402 tariff / quotaТариф без API или исчерпан лимит тарифа (товары, контакты)
403 forbiddenУ ключа нет нужного права
404 not_foundНет такого объекта в вашем проекте
409Конфликт: время занято, запись закрыта, заказ уже отменён
422 content_rejectedТекст, ссылка или фото не прошли проверку содержания
429 rate_limitedСлишком много запросов
5xxСбой на нашей стороне — повторите позже

Страницы, id и время

Списки отдают до limit записей (по умолчанию 50, максимум 200) и next_cursor. Передайте его в cursor, чтобы получить следующую страницу; null — страниц больше нет. Для синхронизации используйте updated_since.

Все id — 32 шестнадцатеричных символа и случайны; заказ — по номеру TW…. Время записи (starts_at) — местное, как его видит владелец; служебные отметки (created_at) — ISO 8601 в UTC.

Защита от дублей

Создание записи принимает заголовок Idempotency-Key (8–80 символов, например номер заказа в вашей системе). Повтор того же запроса с тем же ключом в течение суток вернёт первый ответ с заголовком Idempotent-Replayed: true — второй записи не будет. Тот же ключ с другим телом — 422.

Вебхуки

ТапВей отправит POST с JSON на ваш адрес при событиях проекта. Адрес задаётся в кабинете: CRM → Вебхуки (с тарифа «Про»). Только https://; перенаправления не выполняются.

{
  "id": "3f0c9a1e-7b2d-4c5e-9f8a-1d2e3f4a5b6c",
  "event": "booking.created",
  "created_at": "2026-11-13T12:00:00.000Z",
  "multi_id": 123,
  "payload": {
    "appointment": {
      "id": 4512,
      "client_name": "Мария",
      "client_phone": "+79001234567",
      "starts_at": "2026-11-20 14:00"
    },
    "master": "Анна",
    "service": "Стрижка"
  }
}

Заголовки: X-TapWay-Event, X-TapWay-Event-Id (тот же, что id в теле, не меняется при повторах — по нему отсеивайте дубли), X-TapWay-Timestamp, X-TapWay-Signature-V2: t=…,v1=….

Проверка подписи: HMAC-SHA256 от строки t + "." + сырое тело с секретом вебхука должен совпасть с v1; отклоняйте запросы старше 5 минут.

const crypto = require('crypto');

// rawBody — тело запроса как пришло, до JSON.parse
function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false; // старше 5 минут
  const expected = crypto.createHmac('sha256', secret).update(t + '.' + rawBody).digest('hex');
  return expected.length === parts.v1.length
    && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
$raw = file_get_contents('php://input');
$p = [];
foreach (explode(',', $_SERVER['HTTP_X_TAPWAY_SIGNATURE_V2'] ?? '') as $kv) {
  [$k, $v] = array_pad(explode('=', $kv, 2), 2, '');
  $p[$k] = $v;
}
$ok = isset($p['t'], $p['v1'])
  && abs(time() - (int)$p['t']) <= 300
  && hash_equals(hash_hmac('sha256', $p['t'] . '.' . $raw, $secret), $p['v1']);

Ответьте 2xx за 10 секунд. При ошибке сети, 5xx или 429 повторим 6 раз в течение ~21 часа; на другие 4xx не повторяем; на 410 вебхук выключится. Журнал доставок и кнопка «Проверить» — в кабинете.

СобытиеКогда
form.submitЗаявка с формы
survey.submitОтвет на квиз с контактами
survey.startedНачат квиз
survey.finishedЗавершён квиз
payment.paidОплата по кнопке оплаты
booking.createdНовая запись
booking.rescheduledЗапись перенесена
booking.cancelledЗапись отменена
booking.completedКлиент пришёл
booking.no_showКлиент не пришёл
booking.scheduledЗапись снова активна (смена статуса в кабинете)
booking.syncedЗапись перенесена в CRM из кабинета
order.createdНовый заказ
order.paidЗаказ оплачен
order.shippedЗаказ отправлен
order.cancelledЗаказ отменён
contact.upsertКонтакт создан или изменён
deal.createdСделка создана
deal.updatedСделка изменена
test.pingПроверка из кабинета

Основа

GET /v1/ping

Проверка ключа и связи

Ответ 200

{
  "data": {
    "ok": true,
    "time": "2026-11-13T12:00:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

GET /v1/me

Проект, тариф, права и лимиты ключа

Ответ 200

{
  "data": {
    "project": {
      "id": "fe6dee299ccf49369e79d9e18ca741c1",
      "name": "Студия Анны",
      "address": "mob.bio/studio-anna"
    },
    "tariff": {
      "code": "pro",
      "name": "Про"
    },
    "key": {
      "name": "Сайт студии",
      "prefix": "tw_live_aKpn",
      "scopes": [
        "bookings:read",
        "bookings:write"
      ]
    },
    "rate_limit": {
      "per_minute": 60,
      "per_day": 10000,
      "remaining_minute": 59,
      "remaining_day": 9874
    }
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

Онлайн-запись

GET /v1/booking/resources

Блоки записи: мастера, ресурсы и услуги · право bookings:read

Ответ 200

{
  "data": [
    {
      "block_id": "9db0cf42adc44b4e8c17bdede6b20a02",
      "masters": [
        {
          "id": "m1",
          "name": "Анна",
          "kind": "time",
          "work_start": "10:00",
          "work_end": "20:00",
          "services": [
            {
              "id": "s1",
              "name": "Стрижка",
              "duration_min": 60,
              "price": "1500 ₽",
              "capacity": 1,
              "max_per_booking": 1,
              "start_times": null,
              "min_nights": null,
              "max_nights": null,
              "prepay": null
            }
          ]
        }
      ]
    }
  ]
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

GET /v1/booking/slots

Свободное время на дату · право bookings:read

Для записи по времени — свободные слоты дня. Для посуточных ресурсов — сколько ночей подряд свободно с даты заезда.

ПараметрГдеОписание
block_id обязательнозапросid блока записи
master_id обязательнозапросid мастера или ресурса
service_id обязательнозапросid услуги
date обязательнозапросДата
seatsзапросСколько мест нужно (для групп)

Ответ 200

{
  "data": {
    "kind": "time",
    "date": "2026-11-20",
    "duration_min": 60,
    "slots": [
      {
        "time": "10:00"
      },
      {
        "time": "11:00"
      }
    ]
  }
}

Ошибки

  • 400 — Неверные параметры
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Блок, мастер или услуга не найдены
  • 409 — Запись закрыта (исчерпан лимит записей тарифа)

GET /v1/booking/appointments

Список записей · право bookings:read

ПараметрГдеОписание
fromзапросС даты записи
toзапросПо дату записи
statusзапросscheduled, completed, cancelled или no_show
block_idзапросТолько этот блок
updated_sinceзапросТолько изменённые после этого момента (ISO 8601)
limitзапросСколько записей вернуть, 1–200 (по умолчанию 50)
cursorзапросnext_cursor из предыдущего ответа

Ответ 200

{
  "data": [
    {
      "id": "9a395e452787c014acb54d98d7549a27",
      "status": "scheduled",
      "block_id": "9db0cf42adc44b4e8c17bdede6b20a02",
      "master": {
        "id": "m1",
        "name": "Анна"
      },
      "service": {
        "id": "s1",
        "name": "Стрижка",
        "duration_min": 60
      },
      "starts_at": "2026-11-20 14:00",
      "ends_at": "2026-11-20 15:00",
      "date": "2026-11-20",
      "time": "14:00",
      "nights": null,
      "checkout_date": null,
      "seats": 1,
      "client": {
        "name": "Мария",
        "phone": "+79001234567",
        "email": null
      },
      "comment": "Из CRM",
      "source": "api",
      "prepay": null,
      "created_at": "2026-11-13T12:00:00.000Z",
      "updated_at": "2026-11-13T12:00:00.000Z"
    }
  ],
  "next_cursor": "YzoxMjM0"
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

POST /v1/booking/appointments

Создать запись · право bookings:write

Те же проверки, что у формы на странице: свободное время, места, лимит записей клиента в день, месячный лимит тарифа. Уведомления владельцу, мастеру и клиенту уходят как обычно. Предоплата через API не запрашивается.

ПараметрГдеОписание
Idempotency-KeyзаголовокЗащита от дублей: повтор с тем же ключом (8–80 символов) в течение суток вернёт первый ответ, не создавая второй объект

Тело запроса

ПолеТипОписание
block_id обязательноstringПубличный id: 32 шестнадцатеричных символа
master_id обязательноstring
service_id обязательноstring
date обязательноstringДата YYYY-MM-DD
timestringHH:MM — для записи по времени
nightsintegerДля посуточных
seatsintegerМест (по умолчанию 1)
client обязательноobject
commentstringДо 1000 символов
{
  "block_id": "9db0cf42adc44b4e8c17bdede6b20a02",
  "master_id": "m1",
  "service_id": "s1",
  "date": "2026-11-20",
  "time": "14:00",
  "client": {
    "name": "Анна",
    "phone": "+79001234567"
  },
  "comment": "Из CRM"
}

Ответ 201

{
  "data": {
    "id": "9a395e452787c014acb54d98d7549a27",
    "status": "scheduled",
    "block_id": "9db0cf42adc44b4e8c17bdede6b20a02",
    "master": {
      "id": "m1",
      "name": "Анна"
    },
    "service": {
      "id": "s1",
      "name": "Стрижка",
      "duration_min": 60
    },
    "starts_at": "2026-11-20 14:00",
    "ends_at": "2026-11-20 15:00",
    "date": "2026-11-20",
    "time": "14:00",
    "nights": null,
    "checkout_date": null,
    "seats": 1,
    "client": {
      "name": "Мария",
      "phone": "+79001234567",
      "email": null
    },
    "comment": "Из CRM",
    "source": "api",
    "prepay": null,
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:00:00.000Z"
  }
}

Ошибки

  • 400 — Неверные поля
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Блок, мастер или услуга не найдены
  • 409 — Время занято (slot_unavailable), лимит клиента (client_limit) или запись закрыта (booking_closed)
  • 422 — Idempotency-Key уже использован с другим запросом

GET /v1/booking/appointments/{id}

Одна запись · право bookings:read

ПараметрГдеОписание
id обязательнопутьid записи

Ответ 200

{
  "data": {
    "id": "9a395e452787c014acb54d98d7549a27",
    "status": "scheduled",
    "block_id": "9db0cf42adc44b4e8c17bdede6b20a02",
    "master": {
      "id": "m1",
      "name": "Анна"
    },
    "service": {
      "id": "s1",
      "name": "Стрижка",
      "duration_min": 60
    },
    "starts_at": "2026-11-20 14:00",
    "ends_at": "2026-11-20 15:00",
    "date": "2026-11-20",
    "time": "14:00",
    "nights": null,
    "checkout_date": null,
    "seats": 1,
    "client": {
      "name": "Мария",
      "phone": "+79001234567",
      "email": null
    },
    "comment": "Из CRM",
    "source": "api",
    "prepay": null,
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:00:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найдена

PATCH /v1/booking/appointments/{id}

Сменить статус записи · право bookings:write

completed — пришёл, no_show — не пришёл, cancelled — отмена (клиент получит сообщение, время освободится). Вернуть отменённую запись нельзя — создайте новую.

ПараметрГдеОписание
id обязательнопутьid записи

Тело запроса

ПолеТипОписание
status обязательноstring (scheduled, completed, cancelled, no_show)
{
  "status": "cancelled"
}

Ответ 200

{
  "data": {
    "id": "9a395e452787c014acb54d98d7549a27",
    "status": "cancelled",
    "block_id": "9db0cf42adc44b4e8c17bdede6b20a02",
    "master": {
      "id": "m1",
      "name": "Анна"
    },
    "service": {
      "id": "s1",
      "name": "Стрижка",
      "duration_min": 60
    },
    "starts_at": "2026-11-20 14:00",
    "ends_at": "2026-11-20 15:00",
    "date": "2026-11-20",
    "time": "14:00",
    "nights": null,
    "checkout_date": null,
    "seats": 1,
    "client": {
      "name": "Мария",
      "phone": "+79001234567",
      "email": null
    },
    "comment": "Из CRM",
    "source": "api",
    "prepay": null,
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:00:00.000Z"
  }
}

Ошибки

  • 400 — Неверный статус
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найдена
  • 409 — Нельзя вернуть отменённую

POST /v1/booking/appointments/{id}/reschedule

Перенести запись · право bookings:write

Проверяется, свободно ли новое время (сама запись в занятость не считается). Клиент и мастер получат сообщение о переносе.

ПараметрГдеОписание
id обязательнопутьid записи

Тело запроса

ПолеТипОписание
date обязательноstringДата YYYY-MM-DD
timestringHH:MM
nightsintegerДля посуточных
{
  "date": "2026-11-21",
  "time": "15:00"
}

Ответ 200

{
  "data": {
    "id": "9a395e452787c014acb54d98d7549a27",
    "status": "scheduled",
    "block_id": "9db0cf42adc44b4e8c17bdede6b20a02",
    "master": {
      "id": "m1",
      "name": "Анна"
    },
    "service": {
      "id": "s1",
      "name": "Стрижка",
      "duration_min": 60
    },
    "starts_at": "2026-11-21 15:00",
    "ends_at": "2026-11-21 16:00",
    "date": "2026-11-21",
    "time": "15:00",
    "nights": null,
    "checkout_date": null,
    "seats": 1,
    "client": {
      "name": "Мария",
      "phone": "+79001234567",
      "email": null
    },
    "comment": "Из CRM",
    "source": "api",
    "prepay": null,
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:00:00.000Z"
  }
}

Ошибки

  • 400 — Неверные поля
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найдена
  • 409 — Время занято или запись не активна

Магазин

GET /v1/shop/categories

Категории · право shop:read

Ответ 200

{
  "data": [
    {
      "id": "b6f79eaadf6c11f19760fa163eb739b5",
      "parent_id": null,
      "title": "Свечи",
      "slug": "svechi",
      "description": "Ароматные свечи ручной работы",
      "sort_order": 0,
      "is_active": true
    }
  ]
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

POST /v1/shop/categories

Создать категорию · право shop:write

Один уровень вложенности: подкатегория кладётся только в категорию верхнего уровня.

Тело запроса

ПолеТипОписание
title обязательноstring
slugstring
descriptionstring
parent_idstring | nullПубличный id: 32 шестнадцатеричных символа
sort_orderinteger
is_activeboolean
{
  "title": "Свечи",
  "description": "Ароматные свечи ручной работы"
}

Ответ 201

{
  "data": {
    "id": "b6f79eaadf6c11f19760fa163eb739b5",
    "parent_id": null,
    "title": "Свечи",
    "slug": "svechi",
    "description": "Ароматные свечи ручной работы",
    "sort_order": 0,
    "is_active": true
  }
}

Ошибки

  • 400 — Неверные поля
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Родитель не найден

PATCH /v1/shop/categories/{id}

Изменить категорию · право shop:write

ПараметрГдеОписание
id обязательнопутьid категории

Тело запроса

ПолеТипОписание
titlestring
slugstring
descriptionstring
parent_idstring | nullПубличный id: 32 шестнадцатеричных символа
sort_orderinteger
is_activeboolean
{
  "title": "Соевые свечи",
  "is_active": false
}

Ответ 200

{
  "data": {
    "id": "b6f79eaadf6c11f19760fa163eb739b5",
    "parent_id": null,
    "title": "Свечи",
    "slug": "svechi",
    "description": "Ароматные свечи ручной работы",
    "sort_order": 0,
    "is_active": true
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найдена

DELETE /v1/shop/categories/{id}

Удалить категорию · право shop:write

ПараметрГдеОписание
id обязательнопутьid категории

Ответ 200

{
  "data": {
    "id": "7cc0184d032b083e9a398a0c9076c4dc",
    "deleted": true
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найдена

GET /v1/shop/attributes

Характеристики товаров · право shop:read

Ответ 200

{
  "data": [
    {
      "name": "Аромат",
      "slug": "aromat",
      "is_filter": true
    }
  ]
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

GET /v1/shop/products

Список товаров · право shop:read

ПараметрГдеОписание
activeзапрос1 — только показанные, 0 — только скрытые
skuзапросПо артикулу
category_idзапросИз категории
updated_sinceзапросТолько изменённые после этого момента (ISO 8601)
limitзапросСколько записей вернуть, 1–200 (по умолчанию 50)
cursorзапросnext_cursor из предыдущего ответа

Ответ 200

{
  "data": [
    {
      "id": "7cc0184d032b083e9a398a0c9076c4dc",
      "title": "Свеча «Лаванда»",
      "slug": "svecha-lavanda",
      "sku": "LAV-1",
      "description": "Соевый воск, 40 часов горения",
      "price": 990,
      "compare_at_price": 1200,
      "currency": "RUB",
      "stock": 10,
      "made_to_order": false,
      "lead_days": null,
      "weight_g": 300,
      "dimensions": null,
      "is_active": true,
      "is_digital": false,
      "vat_code": null,
      "sort_order": 0,
      "images": [
        "https://mob.bio/api/media/s3?key=iteration%2Fshop%2F…jpg"
      ],
      "category_ids": [
        "b6f79eaadf6c11f19760fa163eb739b5"
      ],
      "attributes": [
        {
          "name": "Аромат",
          "values": [
            "лаванда"
          ]
        }
      ],
      "variants": [
        {
          "id": "88a3467d6b7aaf2ca805017f59430342",
          "title": "200 мл",
          "sku": "LAV-1-200",
          "price": 990,
          "stock": 5,
          "is_active": true
        }
      ],
      "created_at": "2026-11-13T12:00:00.000Z",
      "updated_at": "2026-11-13T12:00:00.000Z"
    }
  ],
  "next_cursor": "YzoxMjM0"
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

POST /v1/shop/products

Создать товар · право shop:write

Название, описание и варианты проверяются на запрещённое содержание, ссылки в описании — по базе опасных адресов. Фото — только загруженные через POST /shop/images.

Тело запроса

ПолеТипОписание
titlestringДо 255 символов
skustring | nullАртикул, до 64 символов. По нему пакетная загрузка находит товар
slugstringЛатиница, цифры, дефис
descriptionstring | nullДо 60 000 символов
pricenumber
compare_at_pricenumber | null
stockinteger | null
made_to_orderboolean
lead_daysinteger | null
weight_ginteger | null
dimensionsobject | null
is_activeboolean
is_digitalboolean
vat_codeinteger | null
sort_orderinteger
imagesstring[]Только адреса из POST /shop/images или уже стоящие в товарах проекта. До 20
category_idsstring[]Пустой список снимает все категории
attributesobject[]
variantsobject[]Только при создании. До 100
{
  "title": "Свеча «Лаванда»",
  "sku": "LAV-1",
  "price": 990,
  "stock": 10,
  "images": [
    "https://mob.bio/api/media/s3?key=…"
  ],
  "category_ids": [
    "b6f79eaadf6c11f19760fa163eb739b5"
  ],
  "variants": [
    {
      "title": "200 мл",
      "price": 990,
      "stock": 5
    }
  ]
}

Ответ 201

{
  "data": {
    "id": "7cc0184d032b083e9a398a0c9076c4dc",
    "title": "Свеча «Лаванда»",
    "slug": "svecha-lavanda",
    "sku": "LAV-1",
    "description": "Соевый воск, 40 часов горения",
    "price": 990,
    "compare_at_price": 1200,
    "currency": "RUB",
    "stock": 10,
    "made_to_order": false,
    "lead_days": null,
    "weight_g": 300,
    "dimensions": null,
    "is_active": true,
    "is_digital": false,
    "vat_code": null,
    "sort_order": 0,
    "images": [
      "https://mob.bio/api/media/s3?key=iteration%2Fshop%2F…jpg"
    ],
    "category_ids": [
      "b6f79eaadf6c11f19760fa163eb739b5"
    ],
    "attributes": [
      {
        "name": "Аромат",
        "values": [
          "лаванда"
        ]
      }
    ],
    "variants": [
      {
        "id": "88a3467d6b7aaf2ca805017f59430342",
        "title": "200 мл",
        "sku": "LAV-1-200",
        "price": 990,
        "stock": 5,
        "is_active": true
      }
    ],
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:00:00.000Z"
  }
}

Ошибки

  • 400 — Неверные поля или чужие фото
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 422 — Текст не прошёл проверку содержания

GET /v1/shop/products/{id}

Один товар · право shop:read

ПараметрГдеОписание
id обязательнопутьid товара

Ответ 200

{
  "data": {
    "id": "7cc0184d032b083e9a398a0c9076c4dc",
    "title": "Свеча «Лаванда»",
    "slug": "svecha-lavanda",
    "sku": "LAV-1",
    "description": "Соевый воск, 40 часов горения",
    "price": 990,
    "compare_at_price": 1200,
    "currency": "RUB",
    "stock": 10,
    "made_to_order": false,
    "lead_days": null,
    "weight_g": 300,
    "dimensions": null,
    "is_active": true,
    "is_digital": false,
    "vat_code": null,
    "sort_order": 0,
    "images": [
      "https://mob.bio/api/media/s3?key=iteration%2Fshop%2F…jpg"
    ],
    "category_ids": [
      "b6f79eaadf6c11f19760fa163eb739b5"
    ],
    "attributes": [
      {
        "name": "Аромат",
        "values": [
          "лаванда"
        ]
      }
    ],
    "variants": [
      {
        "id": "88a3467d6b7aaf2ca805017f59430342",
        "title": "200 мл",
        "sku": "LAV-1-200",
        "price": 990,
        "stock": 5,
        "is_active": true
      }
    ],
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:00:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

PATCH /v1/shop/products/{id}

Изменить товар · право shop:write

Передавайте только меняющиеся поля. Варианты меняются своими методами.

ПараметрГдеОписание
id обязательнопутьid товара

Тело запроса

ПолеТипОписание
titlestringДо 255 символов
skustring | nullАртикул, до 64 символов. По нему пакетная загрузка находит товар
slugstringЛатиница, цифры, дефис
descriptionstring | nullДо 60 000 символов
pricenumber
compare_at_pricenumber | null
stockinteger | null
made_to_orderboolean
lead_daysinteger | null
weight_ginteger | null
dimensionsobject | null
is_activeboolean
is_digitalboolean
vat_codeinteger | null
sort_orderinteger
imagesstring[]Только адреса из POST /shop/images или уже стоящие в товарах проекта. До 20
category_idsstring[]Пустой список снимает все категории
attributesobject[]
variantsobject[]Только при создании. До 100
{
  "price": 1090,
  "stock": 8
}

Ответ 200

{
  "data": {
    "id": "7cc0184d032b083e9a398a0c9076c4dc",
    "title": "Свеча «Лаванда»",
    "slug": "svecha-lavanda",
    "sku": "LAV-1",
    "description": "Соевый воск, 40 часов горения",
    "price": 990,
    "compare_at_price": 1200,
    "currency": "RUB",
    "stock": 10,
    "made_to_order": false,
    "lead_days": null,
    "weight_g": 300,
    "dimensions": null,
    "is_active": true,
    "is_digital": false,
    "vat_code": null,
    "sort_order": 0,
    "images": [
      "https://mob.bio/api/media/s3?key=iteration%2Fshop%2F…jpg"
    ],
    "category_ids": [
      "b6f79eaadf6c11f19760fa163eb739b5"
    ],
    "attributes": [
      {
        "name": "Аромат",
        "values": [
          "лаванда"
        ]
      }
    ],
    "variants": [
      {
        "id": "88a3467d6b7aaf2ca805017f59430342",
        "title": "200 мл",
        "sku": "LAV-1-200",
        "price": 990,
        "stock": 5,
        "is_active": true
      }
    ],
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:00:00.000Z"
  }
}

Ошибки

  • 400 — Неверные поля
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден
  • 422 — Текст не прошёл проверку

DELETE /v1/shop/products/{id}

Удалить товар · право shop:write

ПараметрГдеОписание
id обязательнопутьid товара

Ответ 200

{
  "data": {
    "id": "7cc0184d032b083e9a398a0c9076c4dc",
    "deleted": true
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

POST /v1/shop/products/bulk

Пакетная загрузка до 100 товаров · право shop:write

Товар с артикулом (sku), который уже есть в магазине, обновляется (без вариантов), остальные создаются. Ошибка одной позиции не останавливает остальные. Не больше 60 пакетов в час на ключ.

Тело запроса

ПолеТипОписание
products обязательноProductInput[]
{
  "products": [
    {
      "sku": "LAV-1",
      "title": "Свеча «Лаванда»",
      "price": 1090,
      "stock": 8
    },
    {
      "sku": "ROSE-1",
      "title": "Свеча «Роза»",
      "price": 890
    }
  ]
}

Ответ 200

{
  "data": [
    {
      "index": 0,
      "ok": true,
      "action": "updated",
      "id": "7cc0184d032b083e9a398a0c9076c4dc"
    },
    {
      "index": 1,
      "ok": false,
      "error": {
        "code": "invalid",
        "message": "Проверьте поля: title"
      }
    }
  ]
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

POST /v1/shop/products/bulk-delete

Удалить до 500 товаров · право shop:write

Тело запроса

ПолеТипОписание
ids обязательноstring[]
{
  "ids": [
    "7cc0184d032b083e9a398a0c9076c4dc"
  ]
}

Ответ 200

{
  "data": {
    "deleted": 1
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

POST /v1/shop/products/{id}/variants

Добавить вариант · право shop:write

ПараметрГдеОписание
id обязательнопутьid товара

Тело запроса

ПолеТипОписание
title обязательноstring
skustring
pricenumber | null
stockinteger | null
is_activeboolean
{
  "title": "400 мл",
  "price": 1590,
  "stock": 3
}

Ответ 201

{
  "data": {
    "id": "88a3467d6b7aaf2ca805017f59430342",
    "title": "200 мл",
    "sku": "LAV-1-200",
    "price": 990,
    "stock": 5,
    "is_active": true
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Товар не найден

PATCH /v1/shop/products/{id}/variants/{vid}

Изменить вариант · право shop:write

ПараметрГдеОписание
id обязательнопутьid товара
vid обязательнопутьid варианта

Тело запроса

ПолеТипОписание
titlestring
skustring
pricenumber | null
stockinteger | null
is_activeboolean
{
  "stock": 7
}

Ответ 200

{
  "data": {
    "id": "88a3467d6b7aaf2ca805017f59430342",
    "title": "200 мл",
    "sku": "LAV-1-200",
    "price": 990,
    "stock": 5,
    "is_active": true
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

DELETE /v1/shop/products/{id}/variants/{vid}

Удалить вариант · право shop:write

ПараметрГдеОписание
id обязательнопутьid товара
vid обязательнопутьid варианта

Ответ 200

{
  "data": {
    "id": "7cc0184d032b083e9a398a0c9076c4dc",
    "deleted": true
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

POST /v1/shop/images

Загрузить фото товара · право shop:write

multipart/form-data, поле file: PNG, JPEG, WebP, GIF, AVIF, до 8 МБ. Фото проверяется на откровенное содержание до сохранения. Верните url в images товара. Не больше 300 фото в час на ключ.

Тело запроса — multipart/form-data

curl -X POST https://api.tapway.me/v1/shop/images \
  -H "Authorization: Bearer tw_live_…" \
  -F "file=@photo.jpg"

Ответ 201

{
  "data": {
    "url": "https://mob.bio/api/media/s3?key=iteration%2Fshop%2F1794579344013-b1b2.jpg"
  }
}

Ошибки

  • 400 — Не изображение
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 413 — Больше 8 МБ
  • 422 — Фото не прошло проверку

GET /v1/shop/orders

Список заказов · право shop:read

ПараметрГдеОписание
statusзапросСтатус заказа
payment_statusзапросСтатус оплаты
fromзапросСоздан с даты
toзапросСоздан по дату
updated_sinceзапросТолько изменённые после этого момента (ISO 8601)
limitзапросСколько записей вернуть, 1–200 (по умолчанию 50)
cursorзапросnext_cursor из предыдущего ответа

Ответ 200

{
  "data": [
    {
      "id": "TWMHX2K1A9F3C0D4E5B6A7C8D9",
      "status": "paid",
      "payment_status": "paid",
      "fulfillment_status": "unfulfilled",
      "total": 2280,
      "items_total": 1980,
      "delivery_cost": 300,
      "currency": "RUB",
      "customer": {
        "name": "Мария",
        "phone": "+79001234567",
        "email": "maria@example.com"
      },
      "delivery": {
        "type": "courier",
        "address": "Москва, ул. Лесная, 5",
        "pickup_point": null,
        "tracking_url": null
      },
      "notes": "Позвоните за час",
      "admin_notes": null,
      "fields": [],
      "items": [
        {
          "product_id": "7cc0184d032b083e9a398a0c9076c4dc",
          "variant_id": "88a3467d6b7aaf2ca805017f59430342",
          "title": "Свеча «Лаванда» 200 мл",
          "qty": 2,
          "price": 990
        }
      ],
      "paid_at": "2026-11-13T12:05:00.000Z",
      "refunded_at": null,
      "created_at": "2026-11-13T12:00:00.000Z",
      "updated_at": "2026-11-13T12:05:00.000Z"
    }
  ],
  "next_cursor": "YzoxMjM0"
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

GET /v1/shop/orders/{id}

Один заказ по номеру · право shop:read

ПараметрГдеОписание
id обязательнопутьНомер заказа TW…

Ответ 200

{
  "data": {
    "id": "TWMHX2K1A9F3C0D4E5B6A7C8D9",
    "status": "paid",
    "payment_status": "paid",
    "fulfillment_status": "unfulfilled",
    "total": 2280,
    "items_total": 1980,
    "delivery_cost": 300,
    "currency": "RUB",
    "customer": {
      "name": "Мария",
      "phone": "+79001234567",
      "email": "maria@example.com"
    },
    "delivery": {
      "type": "courier",
      "address": "Москва, ул. Лесная, 5",
      "pickup_point": null,
      "tracking_url": null
    },
    "notes": "Позвоните за час",
    "admin_notes": null,
    "fields": [],
    "items": [
      {
        "product_id": "7cc0184d032b083e9a398a0c9076c4dc",
        "variant_id": "88a3467d6b7aaf2ca805017f59430342",
        "title": "Свеча «Лаванда» 200 мл",
        "qty": 2,
        "price": 990
      }
    ],
    "paid_at": "2026-11-13T12:05:00.000Z",
    "refunded_at": null,
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:05:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

PATCH /v1/shop/orders/{id}

Статус, отслеживание, заметка · право shop:write

Отмена возвращает остатки на склад, покупатель получает письмо о смене статуса — как из кабинета. Отменённый или возвращённый заказ не меняется. Отправления СДЭК/Яндекс через API не создаются.

ПараметрГдеОписание
id обязательнопутьНомер заказа TW…

Тело запроса

ПолеТипОписание
statusstring (new, pending, confirmed, paid, processing, shipped, completed, cancelled, refunded)
tracking_urlstringhttps://…
admin_notesstring
{
  "status": "shipped",
  "tracking_url": "https://www.cdek.ru/ru/tracking?order_id=123"
}

Ответ 200

{
  "data": {
    "id": "TWMHX2K1A9F3C0D4E5B6A7C8D9",
    "status": "shipped",
    "payment_status": "paid",
    "fulfillment_status": "unfulfilled",
    "total": 2280,
    "items_total": 1980,
    "delivery_cost": 300,
    "currency": "RUB",
    "customer": {
      "name": "Мария",
      "phone": "+79001234567",
      "email": "maria@example.com"
    },
    "delivery": {
      "type": "courier",
      "address": "Москва, ул. Лесная, 5",
      "pickup_point": null,
      "tracking_url": "https://www.cdek.ru/ru/tracking?order_id=123"
    },
    "notes": "Позвоните за час",
    "admin_notes": null,
    "fields": [],
    "items": [
      {
        "product_id": "7cc0184d032b083e9a398a0c9076c4dc",
        "variant_id": "88a3467d6b7aaf2ca805017f59430342",
        "title": "Свеча «Лаванда» 200 мл",
        "qty": 2,
        "price": 990
      }
    ],
    "paid_at": "2026-11-13T12:05:00.000Z",
    "refunded_at": null,
    "created_at": "2026-11-13T12:00:00.000Z",
    "updated_at": "2026-11-13T12:05:00.000Z"
  }
}

Ошибки

  • 400 — Неверные поля
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден
  • 409 — Заказ уже отменён или возвращён

GET /v1/shop/reviews

Отзывы · право shop:read

ПараметрГдеОписание
statusзапросpending, published или hidden
limitзапросСколько записей вернуть, 1–200 (по умолчанию 50)
cursorзапросnext_cursor из предыдущего ответа

Ответ 200

{
  "data": [
    {
      "id": "5d1e0c7a9b2f4e6d8c3a1b0f9e8d7c6b",
      "product_id": "7cc0184d032b083e9a398a0c9076c4dc",
      "author_name": "Ольга",
      "rating": 5,
      "body": "Пахнет чудесно, горит долго",
      "status": "published",
      "is_buyer": true,
      "reply": "Спасибо!",
      "created_at": "2026-11-12T09:00:00.000Z",
      "published_at": "2026-11-12T10:00:00.000Z"
    }
  ],
  "next_cursor": "YzoxMjM0"
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

PATCH /v1/shop/reviews/{id}

Опубликовать, скрыть, ответить · право shop:write

ПараметрГдеОписание
id обязательнопутьid отзыва

Тело запроса

ПолеТипОписание
statusstring (pending, published, hidden)
replystring | null
{
  "status": "published",
  "reply": "Спасибо за отзыв!"
}

Ответ 200

{
  "data": {
    "id": "5d1e0c7a9b2f4e6d8c3a1b0f9e8d7c6b",
    "product_id": "7cc0184d032b083e9a398a0c9076c4dc",
    "author_name": "Ольга",
    "rating": 5,
    "body": "Пахнет чудесно, горит долго",
    "status": "published",
    "is_buyer": true,
    "reply": "Спасибо!",
    "created_at": "2026-11-12T09:00:00.000Z",
    "published_at": "2026-11-12T10:00:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

DELETE /v1/shop/reviews/{id}

Удалить отзыв · право shop:write

ПараметрГдеОписание
id обязательнопутьid отзыва

Ответ 200

{
  "data": {
    "id": "7cc0184d032b083e9a398a0c9076c4dc",
    "deleted": true
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

Заявки и квизы

GET /v1/leads/forms

Заявки с форм мультиссылки и сайта · право leads:read

ПараметрГдеОписание
fromзапросС даты
toзапросПо дату
limitзапросСколько записей вернуть, 1–200 (по умолчанию 50)
cursorзапросnext_cursor из предыдущего ответа

Ответ 200

{
  "data": [
    {
      "id": "2b7f0c9e4d3a4f1e8a6c5d2b1e0f9a8c",
      "block_id": "4f3e2d1c0b9a48b7a6c5d4e3f2a1b0c9",
      "name": "Ольга",
      "phone": "+79165551230",
      "email": null,
      "fields": {
        "name": "Ольга",
        "phone": "+79165551230",
        "message": "Хочу на консультацию"
      },
      "created_at": "2026-11-13T09:14:00.000Z"
    }
  ],
  "next_cursor": "YzoxMjM0"
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

GET /v1/leads/surveys

Квизы и опросы · право leads:read

Ответ 200

{
  "data": [
    {
      "id": "c1d2e3f4a5b6478899aabbccddeeff00",
      "title": "Подбор ухода",
      "mode": "quiz",
      "status": "published",
      "slug": "podbor-uhoda",
      "responses": 42,
      "created_at": "2026-10-01T08:00:00.000Z"
    }
  ]
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

GET /v1/leads/surveys/{id}/responses

Ответы квиза · право leads:read

По умолчанию — только завершённые. finished=all — вместе с брошенными на полпути.

ПараметрГдеОписание
id обязательнопутьid квиза
finishedзапросall — все ответы
updated_sinceзапросТолько изменённые после этого момента (ISO 8601)
limitзапросСколько записей вернуть, 1–200 (по умолчанию 50)
cursorзапросnext_cursor из предыдущего ответа

Ответ 200

{
  "data": [
    {
      "id": "0f1e2d3c4b5a49687766554433221100",
      "finished": true,
      "score": 3,
      "result": "Уход для сухой кожи",
      "answers": [
        {
          "question": "Тип кожи",
          "answer": "Сухая"
        },
        {
          "question": "Что важнее всего?",
          "answer": "Увлажнение"
        }
      ],
      "contact": {
        "id": "45e54a7f7c4b74942c83642581dc26c4",
        "name": "Вика",
        "phone": "+79001234567",
        "email": null
      },
      "started_at": "2026-11-13T10:00:00.000Z",
      "finished_at": "2026-11-13T10:02:00.000Z"
    }
  ],
  "next_cursor": "YzoxMjM0"
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Квиз не найден

CRM

GET /v1/crm/contacts

Контакты · право crm:read

ПараметрГдеОписание
qзапросПоиск по имени, телефону, почте
updated_sinceзапросТолько изменённые после этого момента (ISO 8601)
limitзапросСколько записей вернуть, 1–200 (по умолчанию 50)
cursorзапросnext_cursor из предыдущего ответа

Ответ 200

{
  "data": [
    {
      "id": "45e54a7f7c4b74942c83642581dc26c4",
      "name": "Вика",
      "phone": "+79001234567",
      "email": "vika@example.com",
      "telegram": "@vika",
      "source": "api",
      "created_at": "2026-11-13T10:00:00.000Z",
      "updated_at": "2026-11-13T10:05:00.000Z"
    }
  ],
  "next_cursor": "YzoxMjM0"
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

POST /v1/crm/contacts

Создать или обновить контакт · право crm:write

Контакт с тем же телефоном (последние 10 цифр) или почтой обновляется — ответ 200 и created=false. Новый — 201. Новый контакт упирается в лимит контактов тарифа.

Тело запроса

ПолеТипОписание
namestring
phonestring
emailstring
telegramstring
{
  "name": "Вика",
  "phone": "+79001234567",
  "email": "vika@example.com"
}

Ответ 201

{
  "data": {
    "id": "45e54a7f7c4b74942c83642581dc26c4",
    "name": "Вика",
    "phone": "+79001234567",
    "email": "vika@example.com",
    "telegram": "@vika",
    "source": "api",
    "created_at": "2026-11-13T10:00:00.000Z",
    "updated_at": "2026-11-13T10:05:00.000Z"
  },
  "created": true
}

Ошибки

  • 400 — Нужны name, phone или email
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

GET /v1/crm/contacts/{id}

Один контакт · право crm:read

ПараметрГдеОписание
id обязательнопутьid контакта

Ответ 200

{
  "data": {
    "id": "45e54a7f7c4b74942c83642581dc26c4",
    "name": "Вика",
    "phone": "+79001234567",
    "email": "vika@example.com",
    "telegram": "@vika",
    "source": "api",
    "created_at": "2026-11-13T10:00:00.000Z",
    "updated_at": "2026-11-13T10:05:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

PATCH /v1/crm/contacts/{id}

Изменить контакт · право crm:write

ПараметрГдеОписание
id обязательнопутьid контакта

Тело запроса

ПолеТипОписание
namestring | null
phonestring | null
emailstring | null
telegramstring | null
{
  "telegram": "@vika"
}

Ответ 200

{
  "data": {
    "id": "45e54a7f7c4b74942c83642581dc26c4",
    "name": "Вика",
    "phone": "+79001234567",
    "email": "vika@example.com",
    "telegram": "@vika",
    "source": "api",
    "created_at": "2026-11-13T10:00:00.000Z",
    "updated_at": "2026-11-13T10:05:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найден

GET /v1/crm/deals

Сделки · право crm:read

ПараметрГдеОписание
stageзапросСтадия
contact_idзапросСделки контакта
updated_sinceзапросТолько изменённые после этого момента (ISO 8601)
limitзапросСколько записей вернуть, 1–200 (по умолчанию 50)
cursorзапросnext_cursor из предыдущего ответа

Ответ 200

{
  "data": [
    {
      "id": "9ea5407a0603f126bbe547928069239c",
      "title": "Курс ухода",
      "stage": "won",
      "amount": 4900,
      "notes": null,
      "contact": {
        "id": "45e54a7f7c4b74942c83642581dc26c4",
        "name": "Вика",
        "phone": "+79001234567",
        "email": "vika@example.com",
        "telegram": "@vika",
        "source": "api",
        "created_at": "2026-11-13T10:00:00.000Z",
        "updated_at": "2026-11-13T10:05:00.000Z"
      },
      "order_id": null,
      "appointment_id": null,
      "created_at": "2026-11-13T10:10:00.000Z",
      "updated_at": "2026-11-13T11:00:00.000Z"
    }
  ],
  "next_cursor": "YzoxMjM0"
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа

POST /v1/crm/deals

Создать сделку · право crm:write

Контакт — по contact_id или полями contact (найдём по телефону/почте или создадим). При исчерпанном лимите контактов сделка создаётся без контакта.

Тело запроса

ПолеТипОписание
title обязательноstring
stagestringПо умолчанию new
amountnumber | null
notesstring | null
contact_idstringПубличный id: 32 шестнадцатеричных символа
contactobject
{
  "title": "Курс ухода",
  "stage": "new",
  "amount": 4900,
  "contact": {
    "name": "Вика",
    "phone": "+79001234567"
  }
}

Ответ 201

{
  "data": {
    "id": "9ea5407a0603f126bbe547928069239c",
    "title": "Курс ухода",
    "stage": "new",
    "amount": 4900,
    "notes": null,
    "contact": {
      "id": "45e54a7f7c4b74942c83642581dc26c4",
      "name": "Вика",
      "phone": "+79001234567",
      "email": "vika@example.com",
      "telegram": "@vika",
      "source": "api",
      "created_at": "2026-11-13T10:00:00.000Z",
      "updated_at": "2026-11-13T10:05:00.000Z"
    },
    "order_id": null,
    "appointment_id": null,
    "created_at": "2026-11-13T10:10:00.000Z",
    "updated_at": "2026-11-13T11:00:00.000Z"
  }
}

Ошибки

  • 400 — Неверные поля
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Контакт не найден

GET /v1/crm/deals/{id}

Одна сделка · право crm:read

ПараметрГдеОписание
id обязательнопутьid сделки

Ответ 200

{
  "data": {
    "id": "9ea5407a0603f126bbe547928069239c",
    "title": "Курс ухода",
    "stage": "won",
    "amount": 4900,
    "notes": null,
    "contact": {
      "id": "45e54a7f7c4b74942c83642581dc26c4",
      "name": "Вика",
      "phone": "+79001234567",
      "email": "vika@example.com",
      "telegram": "@vika",
      "source": "api",
      "created_at": "2026-11-13T10:00:00.000Z",
      "updated_at": "2026-11-13T10:05:00.000Z"
    },
    "order_id": null,
    "appointment_id": null,
    "created_at": "2026-11-13T10:10:00.000Z",
    "updated_at": "2026-11-13T11:00:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найдена

PATCH /v1/crm/deals/{id}

Изменить сделку · право crm:write

ПараметрГдеОписание
id обязательнопутьid сделки

Тело запроса

ПолеТипОписание
titlestring
stagestring
amountnumber | null
notesstring | null
contact_idstring | nullПубличный id: 32 шестнадцатеричных символа
{
  "stage": "won"
}

Ответ 200

{
  "data": {
    "id": "9ea5407a0603f126bbe547928069239c",
    "title": "Курс ухода",
    "stage": "won",
    "amount": 4900,
    "notes": null,
    "contact": {
      "id": "45e54a7f7c4b74942c83642581dc26c4",
      "name": "Вика",
      "phone": "+79001234567",
      "email": "vika@example.com",
      "telegram": "@vika",
      "source": "api",
      "created_at": "2026-11-13T10:00:00.000Z",
      "updated_at": "2026-11-13T10:05:00.000Z"
    },
    "order_id": null,
    "appointment_id": null,
    "created_at": "2026-11-13T10:10:00.000Z",
    "updated_at": "2026-11-13T11:00:00.000Z"
  }
}

Ошибки

  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 404 — Не найдена

Статистика

GET /v1/stats

Посещения и клики за период · право stats:read

Сводные цифры без отдельных визитов. Без параметров — последние 7 дней. Боты не учитываются.

ПараметрГдеОписание
periodзапросtoday, yesterday, week, month или year
fromзапросНачало периода (до 366 дней)
toзапросКонец периода
surfaceзапросmulti — мультиссылка (по умолчанию), website — сайт, all — всё

Ответ 200

{
  "data": {
    "period": {
      "kind": "week",
      "from": null,
      "to": null,
      "days": null,
      "granularity": "day",
      "surface": "multi"
    },
    "totals": {
      "visits": 1240,
      "unique_visitors": 860,
      "clicks": 312,
      "unique_clicks": 240
    },
    "series": [
      {
        "t": "2026-11-12",
        "hits": 180,
        "unique_hits": 131,
        "clicks": 44
      }
    ],
    "top_links": [
      {
        "url": "https://t.me/studio_anna",
        "clicks": 120
      }
    ],
    "top_blocks": [
      {
        "block_id": "9db0cf42adc44b4e8c17bdede6b20a02",
        "label": "Онлайн-запись",
        "clicks": 96
      }
    ],
    "top_referrers": [
      {
        "referer": "instagram.com",
        "cnt": 410
      }
    ],
    "top_geo": [
      {
        "country": "Россия",
        "city": "Москва",
        "cnt": 520
      }
    ],
    "utm": {
      "sources": [
        {
          "value": "vk",
          "hits": 210,
          "uniqueHits": 160
        }
      ],
      "mediums": [],
      "campaigns": [],
      "combos": []
    }
  }
}

Ошибки

  • 400 — Неверные параметры
  • 402 — Тариф без API (ниже «Про») или исчерпан лимит тарифа
  • 503 — Статистика временно недоступна