Перейти к основному содержимому

Заказы Wildberries и Ozon в таблицу

Скрипт по расписанию забирает новые и изменённые заказы через API продавца и записывает их на лист. Повторные выгрузки обновляют строки, а не дублируют их. По таким данным удобно строить сводные по товарам, складам и дням.

Что понадобится:

  • таблица Coverse на тарифе «Бизнес» или выше;
  • доступ к кабинету продавца, где выпускаются ключи API;
  • 15 минут.
API маркетплейсов меняются

Wildberries и Ozon регулярно меняют методы и поля API продавца. Перед настройкой сверьте адреса методов и названия полей с документацией: Wildberries, Ozon. Если метод перестал работать, код ниже легко поправить под новый: меняются только адрес и названия полей.

Wildberries​

1. Выпустите токен​

  1. В кабинете продавца откройте меню профиля → «Интеграции по API» → «Создать токен».
  2. Выберите категорию «Статистика» и доступ только на чтение.
  3. Скопируйте токен: он показывается один раз и действует 180 дней.
  4. В редакторе скрипта на вкладке «Секреты» добавьте секрет WB_TOKEN.

2. Код скрипта​

Скрипт запрашивает заказы, изменившиеся после прошлой выгрузки, и запоминает отметку в «Памяти». Одна строка — один товар в заказе, её номер в Wildberries — srid.

const SHEET = "Заказы WB";
const FIRST_DAYS = 3;

function main() {
const token = Secrets.get("WB_TOKEN");
if (!token) throw new Error("Добавьте секрет WB_TOKEN");

const since = Properties.script.get("wbDateFrom")
|| Utilities.formatDate(Utilities.addDays(Utilities.today(), -FIRST_DAYS), "yyyy-MM-dd'T'HH:mm:ss", "Europe/Moscow");

const response = Http.get("https://statistics-api.wildberries.ru/api/v1/supplier/orders", {
headers: { Authorization: token },
query: { dateFrom: since, flag: 0 },
});
if (response.status === 429) {
console.log("Wildberries просит подождать, следующий запуск продолжит");
return;
}
if (!response.ok) throw new Error("Wildberries ответил с кодом " + response.status + ": " + response.text().slice(0, 300));

const orders = response.json();
if (orders.length === 0) {
console.log("Новых изменений нет");
return;
}

upsert(SHEET, ["srid", "Дата", "Артикул", "nmId", "Склад", "Цена со скидкой", "Отменён", "Изменён"], orders.map((order) => [
asText(order.srid),
Utilities.toDate(String(order.date).slice(0, 19)) || "",
asText(order.supplierArticle),
order.nmId,
asText(order.warehouseName),
Number(order.priceWithDisc) || 0,
order.isCancel === true,
Utilities.toDate(String(order.lastChangeDate).slice(0, 19)) || "",
]));

Coverse.table.flush();
Properties.script.set("wbDateFrom", orders[orders.length - 1].lastChangeDate);
console.log("Получено строк:", orders.length);
}

function upsert(name, header, rows) {
const sheet = Coverse.table.getSheetByName(name) || Coverse.table.insertSheet(name);
if (sheet.getLastRow() === 0) sheet.appendRow(header);

const last = sheet.getLastRow();
const keys = sheet.getRange(1, 1, last, 1).getValues();
const index = new Map(keys.map((row, i) => [String(row[0]), i + 1]));
const added = new Map();

for (const row of rows) {
const key = String(row[0]);
const at = index.get(key);
if (at === undefined) {
added.set(key, row);
} else {
sheet.getRange(at, 1, 1, header.length).setValues([row]);
}
}

if (added.size > 0) sheet.appendRows([...added.values()]);
}

function asText(value) {
const text = String(value === undefined || value === null ? "" : value);
return text.charAt(0) === "=" ? "'" + text : text;
}

Что важно в коде:

  • Wildberries отдаёт заказы, у которых lastChangeDate позже dateFrom. Следующая выгрузка начинается с lastChangeDate последней строки, поэтому изменения статуса, например отмена, тоже доезжают и обновляют строку по srid.
  • Первая выгрузка берёт заказы за последние FIRST_DAYS дня. Ответ API больше 2 МБ скрипт не примет, и отметка в «Памяти» тогда не сдвинется: каждый следующий запуск будет запрашивать тот же период и падать с той же ошибкой. В этом случае уменьшите FIRST_DAYS или впишите на вкладке «Память» ключ wbDateFrom с более поздней датой, например 2026-10-19T00:00:00. Так же поступите, если триггер был долго выключен.
  • Время в API Wildberries московское. Скрипт записывает его как есть, в таблице оно совпадает с кабинетом продавца.
  • Метод статистики заказов разрешает примерно один запрос в минуту. Если Wildberries отвечает 429, скрипт выходит, а следующий запуск продолжит.
  • upsert читает только первый столбец с ключами, переписывает изменившиеся строки и дописывает новые. Свои пометки ведите в столбцах правее выгрузки.
  • Скрипт за один запуск читает не больше 200 000 ячеек, поэтому лист с ключами в первом столбце выдержит до нескольких десятков тысяч строк. Старые заказы время от времени переносите на архивный лист.

3. Включите расписание​

На вкладке «Триггеры» добавьте «По расписанию», каждые 30 минут или каждый час: данные статистики в Wildberries обновляются раз в 30 минут.

Ozon​

1. Выпустите ключ​

  1. В кабинете продавца Ozon в настройках откройте раздел Seller API и создайте ключ с ролью, которой доступен список отправлений.
  2. Запишите Client ID и ключ.
  3. На вкладке «Секреты» добавьте OZON_CLIENT_ID и OZON_API_KEY.

2. Код скрипта​

Скрипт выгружает отправления FBS за последние двое суток и обновляет их статусы. Одна строка — один товар в отправлении.

const SHEET = "Отправления Ozon";
const DAYS = 2;
const LIMIT = 50;
const MAX_PAGES = 20;

function main() {
const clientId = Secrets.get("OZON_CLIENT_ID");
const apiKey = Secrets.get("OZON_API_KEY");
if (!clientId || !apiKey) throw new Error("Добавьте секреты OZON_CLIENT_ID и OZON_API_KEY");

const iso = (date) => Utilities.formatDate(date, "yyyy-MM-dd'T'HH:mm:ss'Z'", "UTC");
const filter = { since: iso(Utilities.addDays(new Date(), -DAYS)), to: iso(new Date()) };
const rows = [];

for (let page = 0; page < MAX_PAGES; page++) {
const response = Http.post("https://api-seller.ozon.ru/v3/posting/fbs/list", {
dir: "ASC",
filter: filter,
limit: LIMIT,
offset: page * LIMIT,
}, {
headers: { "Client-Id": clientId, "Api-Key": apiKey },
});
if (!response.ok) throw new Error("Ozon ответил с кодом " + response.status + ": " + response.text().slice(0, 300));

const result = response.json().result;
for (const posting of result.postings) {
for (const product of posting.products) {
rows.push([
asText(posting.posting_number + ":" + product.offer_id),
asText(posting.posting_number),
asText(posting.status),
Utilities.toDate(posting.in_process_at) || "",
asText(product.offer_id),
asText(product.name),
product.quantity,
Number(product.price) || 0,
]);
}
}
if (!result.has_next) break;
if (page === MAX_PAGES - 1) console.warn("Отправлений больше " + LIMIT * MAX_PAGES + ", остальные загрузит следующий запуск или уменьшите DAYS");
}

if (rows.length === 0) {
console.log("Отправлений нет");
return;
}

upsert(SHEET, ["Ключ", "Отправление", "Статус", "В обработке с", "Артикул", "Товар", "Кол-во", "Цена"], rows);
console.log("Обработано строк:", rows.length);
}

Этот код вставляйте в отдельный скрипт: в нём свои SHEET и main, в одном скрипте с примером для Wildberries они бы совпали. Ниже вставьте функции upsert и asText из примера для Wildberries.

Что важно в коде:

  • Скрипт запрашивает по 50 отправлений на страницу, поле has_next говорит, есть ли следующая. Если отправлений больше, чем помещается в MAX_PAGES страниц, в журнале появится предупреждение.
  • Ключ строки — номер отправления и артикул: в одном отправлении может быть несколько товаров.
  • Цена товара приходит текстом, скрипт превращает её в число.
  • Время in_process_at Ozon передаёт в UTC, Utilities.toDate разбирает его с учётом пояса.
  • Для отправлений FBO у Ozon отдельный метод /v2/posting/fbo/list с похожими полями.

3. Включите расписание​

На вкладке «Триггеры» добавьте «По расписанию», например каждый час.

Если что-то не работает​

СимптомПричинаЧто сделать
код 401токен неверный, истёк или выпущен не для той категориивыпустите новый токен с нужной категорией и сохраните его в секрет
код 403 у Ozonу ключа нет роли для этого методасоздайте ключ с нужной ролью
код 429слишком частые запросызапускайте реже; у Wildberries статистика заказов — около запроса в минуту
код 404 или «метод не найден»маркетплейс отключил или переименовал методсверьте адрес с документацией маркетплейса
Http.fetch: ответ больше 2097152 байт.ответ больше 2 МБуменьшите период: FIRST_DAYS или ключ wbDateFrom у Wildberries, DAYS или LIMIT у Ozon
«Превышено время»ответы маркетплейса медленныеуменьшите MAX_PAGES
Too many cells read in one run (max 200000)лист выгрузки слишком большойперенесите старые строки на архивный лист
поле пустоемаркетплейс переименовал полепосмотрите ответ: добавьте console.log(JSON.stringify(orders[0])) и сверьте названия

Частые вопросы​

Как выгружать заказы Wildberries в таблицу?​

Скрипт Coverse по расписанию запрашивает заказы через API статистики Wildberries с токеном категории «Статистика» и обновляет строки при изменении статуса.

Можно ли выгружать отправления Ozon?​

Да, через Seller API: скрипт с ключом Client-Id и Api-Key загружает отправления FBS за последние дни и обновляет их статусы.

Не будет ли дублей при повторной выгрузке?​

Нет. Скрипт находит строку по номеру заказа или отправления и обновляет её, а новые дописывает.

Что дальше​