Skip to content

Operations

Triggering data imports and exporting data out.


Start a sync

POST /api/sync

Runs the ETL immediately instead of waiting for the 06:00 cron job.

Parameter Type Default Description
source string all wb, ozon or all
days integer 30 How far back to import

The request returns as soon as the job has been launched, not when it completes. Poll GET /api/sync/status for progress.

Response

{ "status": "started" }

If an import is already running, the request is refused rather than queued:

{ "status": "already_running", "message": "Synchronisation already in progress" }

This is still a 200. Check the status field rather than the HTTP code.

curl -X POST "http://localhost:8000/api/sync?source=wb&days=7"

Two constraints worth knowing before you rely on this

The job is killed after 15 minutes. A large historical import will exceed that. Run those from the command line with run_etl.py, where nothing times them out.

The subprocess uses absolute paths under /opt/analytics. On an installation anywhere else this endpoint fails immediately while scheduled cron syncs continue to work, because cron invokes the script directly. See Troubleshooting.


Check sync status

GET /api/sync/status

Current state of the import job. Takes no parameters.

Field Type Description
running boolean Whether a job is in progress
status string idle, running (...), done, timeout, or error: ...
started string | null ISO 8601 timestamp of when the current or last job began
log array Last 20 lines of the job's combined output
{
  "running": false,
  "status": "done",
  "started": "2026-07-28T09:14:02.317441",
  "log": ["Wildberries: done", "Ozon: done"]
}

State is held in memory, not in the database. Restarting the API service resets it to idle, and no record of past imports survives a restart. If you need an audit trail of imports, read the cron log on the server instead.


CSV exports

Five endpoints return a CSV file rather than JSON, each mirroring a dashboard section.

Endpoint Contents Parameters
GET /api/export/finance Daily revenue, profit and deductions days (default 30)
GET /api/export/profitability Per-product economics, full history none
GET /api/export/reorder Stock levels and reorder status none
GET /api/export/cards Daily listing statistics days (default 30)
GET /api/export/platform Marketplace comparison none

Each responds with Content-Type: text/csv and a Content-Disposition header carrying a generated filename, so a browser downloads rather than displays the result. Filenames for the windowed exports include the window, for example finance_30d.csv.

curl -OJ "http://localhost:8000/api/export/finance?days=90"

Encoding. Files are UTF-8 with a byte order mark. The mark is there so that Excel opens Cyrillic product names correctly on a double-click instead of showing mojibake. The cost is that some strict CSV parsers read it as part of the first column's name, so strip it when feeding an export into a script.

Empty results. An export with no matching rows still returns a valid CSV containing a single placeholder row, rather than an empty file or an error.