Marketplace ABC: automating Ozon API in 6 sprints
Chemicals distributor BytTorg ran 4,200 SKUs manually and bled 11% of revenue on late-shipment fines. Six sprints later a team of two does the work of five and fines are down to 0.7%.
Creastra Digest
- Ozon Seller API covers 90% of the routine: prices, stock, FBO/FBS via idempotent jobs
- Redis queues plus Node workers beat cron scripts on a warehouse server
- The main risk is rate limits: batch 1,000 SKUs per request and add jittered backoff
In January 2024 BytTorg — a Saint-Petersburg household-chemicals distributor — listed 4,200 SKUs on Ozon and kept three «price updater» operators on payroll. Every morning: open Excel, pull stock from 1C, retype into the seller dashboard. Every week: fines for late shipments because someone forgot to refresh stock. Six sprints later two engineers and a Redis queue do it all.
Sprint 1. Process inventory
Before any automation we spent two weeks on-site logging time-and-motion. We catalogued 14 recurring processes — stock and price updates, FBS label generation, returns handling. Seven of them ate 80% of operator time. We started there.
Sprint 2. Integration scaffold
We stood up a dedicated Node 20 + Fastify service, with Postgres for journals and Redis for queues. Auth to Ozon Seller API via Client-Id and Api-Key in a single secret store. Cardinal rule: the Client-Id never lands in logs.
// Stock-sync worker — idempotent on offer_id
await queue.process('stock-sync', 8, async (job) => {
const batch = job.data.items.slice(0, 1000); // Ozon limit
const res = await ozon.post('/v2/products/stocks', { stocks: batch });
for (const r of res.result) {
if (!r.updated) await journal.warn({ sku: r.offer_id, errors: r.errors });
}
return { updated: res.result.filter(r => r.updated).length };
});Sprint 3. Prices and matrices
BytTorg prices depend on three inputs: purchase cost, logistics leg, category fee. We put the formula in the DB and tied it to Min/Premium/Action tiers — three price levels pushed to Ozon hourly. In parallel, an alert: if a price drops more than 3% below cost, a manager gets a Telegram message and the publish rolls back.
Sprint 4. FBS labels and shipments
- Subscribe to Ozon webhooks for new FBS shipments
- Auto-generate PDF labels and store in S3-compatible storage
- Bulk-print via CUPS — the warehouse operator clicks one button
- Close shipments in the API the moment they leave the dock
- Per-shipment event journal with a 90-day TTL
Sprint 5. Returns and disputes
The dirtiest process. Ozon's returns API splits into several endpoints by type. We wrote a single adapter: event type in, normalised row in our `returns` table out, with reason_code, refund_amount, ozon_id, decision_due_at. The manager works in one screen instead of three dashboard sections.
Sprint 6. Analytics and alerts
On top of Postgres we wired Metabase — yesterday's margin dashboard for the owner, problem-SKU and late-shipment views for ops. Engineer alerts to Telegram: Ozon rate limits, 5xx spikes, 1C→Ozon stock drift above 5%.
Ozon API gotchas
- Endpoint rate limits vary — the «1000 rpm» figure is a myth
- Only some methods are idempotent; the rest need a journal on our side
- Schemas shift without notice — we keep snapshot tests on responses
- Timestamps are not always UTC — we normalise in the worker
- A 200 OK does not mean the update applied — always read the `result`
By the numbers
Across six sprints (12 weeks, two engineers and an analyst), BytTorg's team shrank from five operators to two. Late-shipment fines dropped from 11% of revenue to 0.7%. New-SKU onboarding time fell from 23 minutes to 3.5. Project payback: 4.5 months.