Остановка лида
Остановите автоматическую цепочку одного лида. Новые попытки запрещаются, но уже начатая отправка еще может завершиться.
#Запрос
POST /v1/leads/{id}/stop требует leads:stop и доступа к пространству и кампании лида. id обозначает участие в одной кампании: стоп не останавливает того же человека в других кампаниях и не добавляет его в общий стоп-лист.
Передайте обязательный Idempotency-Key (от 1 до 255 печатных ASCII-символов), Content-Type: application/json и пустой объект {}. Дополнительные поля запрещены. Сохраните уникальный ключ этой операции до запроса; ключ добавления лидов для стопа повторно не используйте.
curl --retry 5 --retry-max-time 300 \
-X POST https://api.melioralab.io/v1/leads/5a7c3e92-1f4b-4d68-9c2e-7b0a6d4f8e31/stop \
-H "Authorization: Bearer $MELIORA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $MELIORA_IDEMPOTENCY_KEY" \
--data-raw '{}'import os
import random
import time
import requests
headers = {
"Authorization": f"Bearer {os.environ['MELIORA_API_KEY']}",
"Content-Type": "application/json",
"Idempotency-Key": os.environ["MELIORA_IDEMPOTENCY_KEY"],
}
for attempt in range(6):
response = requests.post(
"https://api.melioralab.io/v1/leads/5a7c3e92-1f4b-4d68-9c2e-7b0a6d4f8e31/stop",
headers=headers, data=b"{}", timeout=15,
)
if response.status_code in (429, 503) and attempt < 5:
time.sleep(float(response.headers.get("Retry-After", "5")) + random.random())
continue
response.raise_for_status()
command = response.json()
print(command["id"], command["result"])
breakconst headers = {
Authorization: `Bearer ${process.env.MELIORA_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': process.env.MELIORA_IDEMPOTENCY_KEY,
};
for (let attempt = 0; attempt < 6; attempt++) {
const response = await fetch('https://api.melioralab.io/v1/leads/5a7c3e92-1f4b-4d68-9c2e-7b0a6d4f8e31/stop', {
method: 'POST', headers, body: '{}', signal: AbortSignal.timeout(15_000),
});
if ([429, 503].includes(response.status) && attempt < 5) {
const delay = Number(response.headers.get('Retry-After') ?? 5) + Math.random();
await response.body?.cancel();
await new Promise((resolve) => setTimeout(resolve, delay * 1000));
continue;
}
if (!response.ok) throw new Error(`Meliora API ${response.status}: ${await response.text()}`);
const command = await response.json();
console.log(command.id, command.result);
break;
}#Что означает ответ
HTTP 202 возвращает команду с kind=stop, целевым lead_id, пустым items и полями результата:
result.automation_state=stopped: запрет новых автоматических попыток установлен, уже начатой отправки нет.result.automation_state=stopping: запрет установлен, но отправка уже началась.result.send_in_flight=true: эта отправка еще может завершиться. Это не подтверждение ее доставки.result.unknown_outcome_message_ids: непрозрачные идентификаторы отправок, исход которых неизвестен. Не разбирайте их формат.cleanup_pending=true: еще остается уборка остановленных задач. Это поле команды, а неresult.
Команда может сразу завершиться как done или done_with_unknown, а может оставаться accepted или running. Опрашивайте GET /v1/commands/{id} до конечного состояния и завершения уборки. stopped в результате само по себе не заменяет эту проверку.
При чтении лида смотрите automation_stopped, automation_stopped_at, automation_stop_source и объект automation: state (running, stopping, stopped, unknown), stopped_at, source, send_in_flight, unknown_outcome_message_ids. В ответе чтения automation_stopped, automation.send_in_flight и automation.unknown_outcome_message_ids могут быть null, если данные не установлены. null не означает false или пустой массив. Статус участия, например replied, не обязан меняться при стопе.
automation.state=running означает отсутствие установленного стопа на уровне лида, а не разрешение немедленно отправлять: пауза кампании и удержания все еще действуют. В отличие от чтения, результат команды стопа содержит определенный send_in_flight (true или false) и массив unknown_outcome_message_ids.
#Событие и повтор
lead.stopped появляется в ленте событий после завершения начатой отправки и уборки, а не сразу при stopping. В data.stop приходят automation_stopped, stopped_at и source. Схема допускает true, false или null для automation_stopped, время или null для stopped_at, строку или null для source. Для установленного API-стопа ожидаются true и api, но это не константы схемы. Событие подтверждает остановку автоматизации, но не определенность всех прошлых отправок.
Повтор с тем же ключом, лидом и телом возвращает ту же команду с текущим состоянием. При 429/503 выдержите Retry-After, при обрыве сохраните тот же ключ. Повторная остановка с новым ключом тоже безопасна: цепочка не возобновляется, исходное время стопа сохраняется, второго перехода и второго события lead.stopped не создается. Другой лид или операция с уже использованным ключом дают 422 idempotency_key_reused.
#Бюджет и ошибки
Стоп имеет вес 1 и отдельный бюджет: до 2 одновременных запросов, 60 в минуту на ключ и 120 в минуту на кабинет. Он не расходует обычный минутный бюджет кабинета и его обычные места одновременных запросов. Лимиты не гарантируют немедленный ответ; при 429/503 повторяйте после паузы.
403 scope_required означает нехватку права; 403 api_write_disabled означает, что запись еще не включена. Неверное тело дает 422 invalid_request, неверный заголовок 400 invalid_parameter, чужой или недоступный лид 404 not_found. При 503 rate_limiter_unavailable повторите исходный запрос с тем же ключом. Подробности в ошибках и лимитах.