Перейти к содержанию

Стратегия pagination для API в n8n: cursor, offset, checkpoint и безопасный backfill

Обновлено: 2026-05-29

Открыть мой план

Короткий ответ

Pagination strategy в n8n — это правила, по которым workflow забирает много страниц из внешнего API и не теряет данные при лимитах, сбоях, изменениях порядка и повторном запуске. Недостаточно включить pagination в HTTP Request node: нужно понять тип пагинации API, хранить checkpoint, обрабатывать 429/5xx, дедуплицировать объекты и тестировать сценарий “сбой на середине списка”. Если этого не сделать, workflow может пропустить новые сделки, создать дубли, зациклиться на одной странице или выгрузить слишком много данных за один запуск.

Какие типы pagination встречаются

В API обычно встречаются пять вариантов: page + limit, offset + limit, cursor, next_url, created_after/updated_after. Каждый вариант требует своей стратегии. Page pagination проста, но нестабильна, если данные меняются во время выгрузки. Offset pagination удобна для отчётов, но на больших таблицах может быть медленной и давать пропуски при вставках. Cursor pagination лучше подходит для потоковых списков, потому что API возвращает токен следующей страницы. Next URL снижает риск ошибки в выражениях, но требует аккуратного хранения полного URL. Time-window pagination удобна для incremental sync, но требует overlap window и dedupe.

В n8n HTTP Request node поддерживает pagination, но workflow всё равно должен знать правила конкретного API. Нельзя копировать настройки из одного сервиса в другой: у CRM, платежей, маркетплейсов и helpdesk разные правила сортировки, лимиты, next token и поведение при удалённых объектах.

Сначала сделайте “один запрос без pagination”

Перед настройкой pagination выполните один HTTP Request к API без автопрокрутки. Посмотрите: где лежит список элементов, где лежит next, cursor, total, has_more, page, limit; меняется ли порядок; есть ли updated_at; возвращает ли API пустую последнюю страницу; включает ли ответ удалённые объекты; какой максимальный limit; какие заголовки rate limit доступны.

Практическая таблица анализа:

Вопрос Что записать Зачем
Какой тип pagination? cursor / offset / page / next_url / time window От этого зависит выражение в HTTP node
Какой стабильный ID объекта? deal_id, payment_id, ticket_id Для dedupe и upsert
Есть ли updated_at? ISO timestamp или unix time Для incremental sync
Как API сортирует данные? asc/desc, default order Чтобы не пропустить изменения
Как API сообщает конец? null cursor, has_more=false, empty list Чтобы workflow не зациклился
Какие лимиты? 100/min, 429, Retry-After Для batching/retry

Cursor pagination

Cursor pagination обычно самый надёжный вариант для n8n. Первый запрос идёт без cursor или с пустым cursor. API возвращает items и next_cursor. Следующий запрос передаёт next_cursor, пока он не станет пустым.

Пример логики:

{
  "request": {
    "limit": 100,
    "cursor": "{{$response.body.next_cursor}}"
  },
  "stop_when": "{{$response.body.next_cursor === null}}"
}

Риск cursor pagination — потерять checkpoint. Если workflow упал на странице 17, а cursor хранился только в runtime, следующий запуск может начать сначала. Для небольших списков это терпимо, если есть dedupe. Для больших списков лучше хранить checkpoint в Postgres/Data Table: sync_name, last_cursor, last_success_at, items_processed, status. После каждой страницы обновляйте checkpoint, но отмечайте full success только после завершения всей выгрузки.

Offset и page pagination

Offset/page pagination выглядит проще, но требует защиты от изменяющегося списка. Если вы выгружаете offset=0,100,200, а в API в это время добавили новые объекты в начало списка, часть объектов может сдвинуться. Поэтому offset лучше использовать с фиксированным фильтром: например, updated_at >= start and updated_at < end, сортировка по updated_at asc, limit 100.

Если API поддерживает только page pagination без стабильной сортировки, сделайте dedupe по ID и запланируйте регулярную сверку. Для критичных данных не полагайтесь только на offset. Лучше найти endpoint с cursor или time window, либо использовать webhook для новых объектов и periodic sync для сверки.

Time-window и incremental sync

Time-window стратегия нужна для регулярной синхронизации: например, каждый час забрать сделки, изменённые с последнего успешного запуска. Главное правило — добавлять overlap window. Если последний успешный запуск был в 10:00, следующий запрос можно делать не с 10:00, а с 09:55. Да, вы получите дубли, но dedupe/upsert защитит от повторов. Зато вы не потеряете объект, который API записал с задержкой или округлил timestamp.

Пример checkpoint:

{
  "sync_name": "crm_deals_incremental",
  "last_success_watermark": "2026-05-29T09:55:00Z",
  "overlap_minutes": 5,
  "max_page_size": 100,
  "dedupe_key": "deal_id + updated_at"
}

После успешного завершения всех страниц сохраняйте новый watermark. Не обновляйте его после первой страницы: если workflow упадёт на середине, вы можете навсегда пропустить хвост окна.

Dedupe, upsert и порядок обработки

Pagination почти всегда должна заканчиваться upsert, а не blind insert. В CRM используйте external_id; в платежах — payment_id; в тикетах — ticket_id; в маркетплейсе — order_id + status; в аналитике — event_id. Если объект может обновляться, храните source_updated_at и не перезаписывайте более свежую запись старой.

В n8n удобно сделать Code node перед записью:

return items.map(item => {
  const p = item.json;
  return {
    json: {
      external_id: String(p.id),
      source_updated_at: p.updated_at,
      sync_hash: $crypto.createHash('sha256').update(JSON.stringify(p)).digest('hex'),
      payload: p
    }
  };
});

Если $crypto недоступен в вашей среде Code node, замените hash на простое сравнение ключевых полей или вынесите hashing в backend. Смысл не в конкретной функции, а в стабильном признаке изменения объекта.

Rate limits и batching

Большая pagination-выгрузка быстро упирается в rate limits. Настройте batch size, задержку между запросами, Retry on Fail и обработку Retry-After, если API его возвращает. Не надо ставить максимальный limit, если downstream CRM или БД не успевает обрабатывать items. Иногда лучше забирать по 50 и стабильно завершать workflow, чем по 500 и падать на timeout.

Для долгих sync лучше разделить ingestion и processing: первый workflow забирает страницы и пишет сырые объекты в staging table, второй обрабатывает их пачками. Это даёт controlled replay, мониторинг отставания и возможность остановить downstream без потери исходных данных.

Тестирование pagination

Обязательные тесты: API вернул пустой список; API вернул ровно одну страницу; API вернул две страницы; API вернул next_cursor, но следующая страница пустая; на странице 3 случился 429; на странице 5 случился 500; объект появился в overlap window; объект удалён в источнике; порядок объектов изменился; workflow запущен повторно после падения.

Проверяйте не только “сколько items пришло”, но и “сколько уникальных объектов записано”, “сколько обновлено”, “сколько пропущено как дубль”, “какой watermark сохранён”, “можно ли повторить запуск без дублей”. Это и есть production-ready pagination.

Частые ошибки

  • Не хранить watermark/checkpoint вне execution.
  • Использовать offset без стабильной сортировки и dedupe.
  • Обновлять watermark до завершения всех страниц.
  • Игнорировать 429 и Retry-After.
  • Считать total count надёжным источником правды при изменяющемся списке.

Минимальный набор внутренних ссылок

  • /architecture/data-contracts/ — для описания входов и выходов workflow.
  • /architecture/idempotency-keys/ — для защиты от дублей и replay.
  • /architecture/retries-and-dlq/ — для повторов, quarantine и controlled replay.
  • /architecture/observability-metrics/ — для логов, метрик и alerting.
  • /playbooks/production-release-checklist/ — для релиза и smoke tests.

FAQ

Какой тип pagination лучше для n8n?

Cursor или next_url обычно надёжнее offset/page. Для регулярной синхронизации хорошо работает time-window с overlap и dedupe.

Можно ли просто включить pagination в HTTP Request node?

Можно для простых выгрузок. Для production нужны checkpoint, dedupe/upsert, retry, лимиты и тест сценария падения на середине списка.

Что делать, если API не даёт updated_at?

Используйте полный периодический sync с dedupe по ID или храните hash объекта. Для критичных данных дополните sync webhook-событиями.

Как избежать дублей при overlap window?

Записывайте данные через upsert по стабильному external_id и храните source_updated_at или sync_hash.

Где хранить cursor или watermark?

В Postgres, Data Table, Redis или внешнем backend. Главное — не хранить только в runtime execution, если выгрузка большая или критичная.