@qzsy/ozon-seller-premium
v0.2.1
Published
Bun-only TypeScript client for selected Ozon Seller read-only endpoints
Keywords
Readme
@qzsy/ozon-seller-premium
Bun-only、TypeScript、零运行时依赖的 Ozon Seller 选定只读接口客户端。
安全与合规
这是非官方内部只读 API 客户端,不代表 Ozon,接口可能随时变化。
Cookie为高敏感凭据:只用合法授权会话,勿写入仓库、日志、Issue 或聊天- SDK 不会自动登录,不处理验证码 / 2FA,不持久化 Cookie 或响应
- 不提供结算报表导出、文件上传下载、评价回复等写操作或未覆盖能力
- 使用本软件即自行承担授权、合规与接口变化风险(MIT)
安装
bun add @qzsy/ozon-seller-premium仅支持 Bun;使用原生 fetch(可注入自定义实现)。
快速开始
import { OzonSellerClient } from "@qzsy/ozon-seller-premium";
const client = new OzonSellerClient({
cookie: Bun.env.OZON_SELLER_COOKIE ?? "",
companyId: Number(Bun.env.OZON_COMPANY_ID),
});
const premium = await client.account.getPremiumStatus(
Number(Bun.env.OZON_COMPANY_ID),
);建议用环境变量注入凭据,不要在代码里硬编码 Cookie。
客户端配置
new OzonSellerClient({
cookie: string; // 必填:卖家后台会话 Cookie
companyId: number; // 必填:整数公司 ID
baseUrl?: string; // 默认 https://seller.ozon.ru
language?: string; // 默认 ru-RU
pageType?: string; // 默认 "",部分页面接口可能依赖
timeoutMs?: number; // 默认 15000
fetch?: typeof fetch; // 可选:测试或自定义 HTTP
});API 一览
挂载点:client.account · client.redemptions · client.analytics · client.products · client.company · client.chat · client.notice · client.files · client.poll · client.resolve · client.composer
账户 client.account
| 方法 | 说明 |
| --- | --- |
| getRoles() | 当前账号角色列表 |
| getPremiumStatus(companyId) | 指定公司的 Premium 订阅状态 |
| getAnalyticsPremiumStatus() | 分析侧 Premium 状态 |
| getInterfaceState() | 用户界面状态(已解析为对象) |
const roles = await client.account.getRoles();
const ui = await client.account.getInterfaceState();回购分析 client.redemptions
| 方法 | 说明 |
| --- | --- |
| getLevels() | 回购水平分档(low / medium / high) |
| getReasons() | 未回购原因 |
| listGoods(limit?, offset?) | 商品回购列表;默认 limit=7,offset=0;limit 1..1000 |
| getPriceSegments() | 价格段分布 |
| getDynamics() | 近四周动态明细(固定 FourWeeks) |
| getDynamicsTotal() | 近四周动态汇总(固定 FourWeeks) |
| getTopSkuReasons() | Top SKU 未回购原因 |
| getSoldCategoryTree() | 已售类目树;返回 CategoryTreeResponse,可用 flattenSoldCategoryTree() 展平 |
| getDashboard() | 并行拉取上述指标(不含 listGoods),任一失败即整体失败 |
const dash = await client.redemptions.getDashboard();
const goods = await client.redemptions.listGoods(20, 0);图表指标 client.analytics
对应卖家后台「分析 → 图表 → 所有指标」。
import { ANALYTICS_TABLE_METRICS } from "@qzsy/ozon-seller-premium";
const data = await client.analytics.getData({
dateFrom: "2026-07-01",
dateTo: "2026-07-14",
metrics: [...ANALYTICS_TABLE_METRICS], // 长度 1..14
dimensions: ["sku"], // 可选,默认 ["sku"]
limit: 100, // 可选,1..1000,默认 100
offset: 0, // 可选,默认 0
// filters / sort / nameLike / timezone / isGeo / isAction
});| 约束 | 说明 |
| --- | --- |
| metrics | 必填,非空,最多 14 个;未知指标可能被上游静默丢弃 |
| ANALYTICS_TABLE_METRICS | 预置常用表指标集(已 ≤ 14) |
| 常用维度 | sku、day、week、month、brand、category1… |
完整指标 / 维度枚举见包内类型 AnalyticsMetric、AnalyticsDimensionId。
商品 client.products
| 方法 | 说明 |
| --- | --- |
| listByFilter(query?) | 单页列表;按 parts 拉取分片 |
| listAll(query?, maxPages?) | 游标翻页聚合;默认最多 20 页(1..100) |
| listRatingsIndex(options?) | 拉取含评级的商品,返回 Map(键为 sku / offerId) |
// 单页:基础信息 + SKU 来源 + 评级
const page = await client.products.listByFilter({
parts: ["PART_ITEM", "PART_SOURCE", "PART_RATING"],
search: "",
limit: 100,
});
// 多页
const all = await client.products.listAll(
{ parts: ["PART_ITEM", "PART_SOURCE"], limit: 100 },
10,
);
// SKU / offer_id → 星级摘要
const ratings = await client.products.listRatingsIndex({ maxPages: 8 });
const one = ratings.get("123456789");常用 parts:PART_ITEM、PART_SOURCE、PART_RATING、PART_PRICE、PART_STOCKS、PART_STATUSES、PART_MEDIA 等。未请求的分片不会出现在响应中。
listByFilter 还可传 visibility、sortBy、sortDir、cursor、filters 等,详见类型 ProductListByFilterQuery。
公司 client.company
| 方法 | 说明 |
| --- | --- |
| getFinanceInfo(companyId?) | 法人 / 税号 / 合同列表;默认使用客户端 companyId |
const finance = await client.company.getFinanceInfo();
console.log(finance.result.legal_name, finance.result.contracts.length);聊天 client.chat
| 方法 | 说明 |
| --- | --- |
| getGroupsUnreadCount(companyMode?) | 分组未读数;main 为数字字符串;默认 companyMode=seller |
通知 client.notice
| 方法 | 说明 |
| --- | --- |
| list(companyId?) | 通知列表;无通知时 result 为空数组 |
文件桶 client.files
| 方法 | 说明 |
| --- | --- |
| getBuckets() | 只读存储桶名列表(无上传 / 下载) |
问卷 client.poll
| 方法 | 说明 |
| --- | --- |
| getActual({ companyId?, pollType? }) | 当前有效问卷;默认 pollType=NPS;无问卷时返回 {} |
可用 hasActivePoll(res) 判断是否存在 company_poll_id。
路由 Resolve client.resolve
| 方法 | 说明 |
| --- | --- |
| resolve(route, trigger?, sellerId?) | 页面加载 / 闲置触发的 resolve;默认 onPageLoad |
await client.resolve.resolve("/app/analytics/redemptions", "onPageLoad");Composer client.composer
| 方法 | 说明 |
| --- | --- |
| getPage({ url }) | 拉取页面 layout / widgetStates / userInfo 等 |
| getWidget({ asyncData }) | 按 layout 的 asyncData 拉取 widget |
| parseWidgetState(page, stateId?) | 二次解析 widgetStates JSON |
| parseMenuContent(page, stateId?) | 解析侧栏菜单 content |
const page = await client.composer.getPage({
url: "/app/dashboard/main/menu?path_hint=%2Fapp%2Fanalytics%2Fredemptions&companyMode=seller",
});
const menu = client.composer.parseMenuContent(page);错误处理
失败时抛出 OzonSellerError(或其子类 ContractError):
| code | 含义 |
| --- | --- |
| HTTP_ERROR | 非 2xx;可读 error.status |
| INVALID_JSON | 响应不是合法 JSON |
| TIMEOUT | 超过 timeoutMs |
| NETWORK_ERROR | 其它网络失败 |
| CONTRACT_ERROR | 响应形状不符合预期契约 |
部分错误带有 traceId(来自响应头 X-O3-Trace-Id)。错误消息不会包含 Cookie 或完整请求头。
import { OzonSellerError, ContractError } from "@qzsy/ozon-seller-premium";
try {
await client.analytics.getData({ /* ... */ });
} catch (e) {
if (e instanceof ContractError) {
// 形状校验失败
} else if (e instanceof OzonSellerError) {
console.error(e.code, e.status, e.traceId);
}
}能力范围
| 已提供 | 未提供 | | --- | --- | | 角色 / Premium / 界面状态 | 结算报表导出、账期明细流水 | | 回购 levels / reasons / 动态 / 类目树等 | 文件上传 / 下载(仅桶列表) | | 图表 data/v1(metrics ≤ 14) | xapi 遥测埋点 | | 商品 list-by-filter(含评级分片) | 评价回复等写操作 | | 公司 finance-info(法人 / 合同) | | | 聊天未读 / 通知列表 / NPS poll | | | 路由 resolve / Composer page+widget | |
HAR 中 seller.ozon.ru 业务接口均已覆盖;xapi.ozon.ru 埋点不在范围内。
响应只做轻量运行时检查;字段以 TypeScript 类型为准,上游变更时类型与行为可能需要同步更新。
License
MIT
