Заказы Wildberries и Ozon в таблицу
Скрипт по расписанию забирает новые и изменённые заказы через API продавца и записывает их на лист. Повторные выгрузки обновляют строки, а не дублируют их. По таким данным удобно строить сводные по товарам, складам и дням.
Что понадобится:
- таблица Coverse на тарифе «Бизнес» или выше;
- доступ к кабинету продавца, где выпускаются ключи API;
- 15 минут.
Wildberries и Ozon регулярно меняют методы и поля API продавца. Перед настройкой сверьте адреса методов и названия полей с документацией: Wildberries, Ozon. Если метод перестал работать, код ниже легко поправить под новый: меняются только адрес и названия полей.
Wildberries
1. Выпустите токен
- В кабинете продавца откройте меню профиля → «Интеграции по API» → «Создать токен».
- Выберите категорию «Статистика» и доступ только на чтение.
- Скопируйте токен: он показывается один раз и действует 180 дней.
- В редакторе скрипта на вкладке «Секреты» добавьте секрет
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. Выпустите ключ
- В кабинете продавца Ozon в настройках откройте раздел Seller API и создайте ключ с ролью, которой доступен список отправлений.
- Запишите Client ID и ключ.
- На вкладке «Секреты» добавьте
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_atOzon передаёт в 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 за последние дни и обновляет их статусы.
Не будет ли дублей при повторной выгрузке?
Нет. Скрипт находит строку по номеру заказа или отправления и обновляет её, а новые дописывает.
Что дальше
- Быстрые и экономные скрипты
- Сводная по менеджерам каждую неделю: тот же приём для сводной по товарам.
- Остатки и заказы МоегоСклада