MelioraAPI EN
Ранний доступ. Ключи выдаются по запросу. Как получить ключ

Списки возвращаются страницами. Переход к следующей странице выполняется по курсору, без номеров страниц и смещений.

#Ответ со списком

Все списки имеют одинаковую оболочку:

JSON
{
  "object": "list",
  "data": [ { "object": "lead", "id": "5a7c3e92-1f4b-4d68-9c2e-7b0a6d4f8e31" } ],
  "has_more": true,
  "next_cursor": "v1.k1.Qm9hcmRfMWZ4.c3RyaWN0bHlfb3BhcXVl.dGFnX2V4YW1wbGU.bWFjX2V4YW1wbGVfdmFsdWU"
}
ПолеОписание
objectВсегда list.
dataОбъекты текущей страницы.
has_moretrue, если после этой страницы есть еще данные.
next_cursorКурсор следующей страницы. null, если страниц больше нет.
metaДополнительные сведения. Есть у переписки и ленты событий.

Общего числа записей (total) и смещения (offset) нет.

#Параметры

  • limit: сколько объектов вернуть. По умолчанию 50, от 1 до 100. У ленты событий до 200.
  • cursor: значение next_cursor из предыдущего ответа.

Порядок записей фиксирован: от старых к новым по времени создания, при равном времени по id. Параметра сортировки нет. Новые записи попадают в конец списка.

#Как листать

  1. Отправьте первый запрос с нужными фильтрами.
  2. Обработайте data.
  3. Если has_more равен true, повторите запрос с теми же фильтрами и cursor=<next_cursor>.
  4. Остановитесь, когда has_more равен false.
async function listAll(path, params = {}) {
  const items = [];
  let cursor = null;
  do {
    const url = new URL(`https://api.melioralab.io/v1${path}`);
    for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
    if (cursor) url.searchParams.set('cursor', cursor);
    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.MELIORA_API_KEY}` },
    });
    if (!res.ok) throw new Error(`Meliora API: ${res.status} ${res.headers.get('Request-Id')}`);
    const page = await res.json();
    items.push(...page.data);
    cursor = page.has_more ? page.next_cursor : null;
  } while (cursor);
  return items;
}

const leads = await listAll('/leads', { campaign_id: '4d8b2f73-6e1a-4c95-b7d0-8a3f5e2c9b14', limit: 100 });

#Правила курсора

  • Курсор непрозрачен. Не разбирайте и не собирайте его сами, только передавайте обратно.
  • Курсор привязан к запросу. Фильтры следующего запроса должны совпадать с первым. Если фильтры другие, ключ получил другие права или охват, ответ будет 400 cursor_mismatch.
  • limit можно менять между страницами, это не ошибка.
  • Курсор списка живет 15 минут. Просроченный курсор дает 410 cursor_expired: начните обход заново с первой страницы. Курсор ленты событий живет 30 суток, см. Опрос событий.
  • Страница может быть короче limit. Ответ не превышает 1 МиБ, поэтому длинная страница сокращается, а невыданные записи придут на следующей. Ориентируйтесь на has_more, а не на число записей.

#Списки не снимок

Список читается постранично, и между запросами данные могут меняться: лиды добавляются, статусы обновляются. Записи не пропадают и не повторяются из-за смещений, но статус лида на первой странице мог измениться к моменту чтения последней. Если нужно согласованное состояние, сочетайте обход списка с лентой событий: события после якоря покажут, что изменилось.