---
title: "P&L totals for a window"
method: POST
path: "/pnl/summary"
tags: ["P&L"]
---

# P&L totals for a window

`POST /pnl/summary`

Window totals as an ordered waterfall, summed from TikTok's own daily P&L series. Rows are bucketed by order PAID date in the shop's Seller Center timezone. Recent days keep moving as orders settle — check ``data_status`` for freshness.

## Request body

- PnlSummaryRequest — POST /pnl/summary request body — window totals as a P&L waterfall.
  - `start_date` string, date, nullable — Inclusive window start (YYYY-MM-DD). Defaults to 29 days before ``end_date``.
  - `end_date` string, date, nullable — Inclusive window end (YYYY-MM-DD). Defaults to yesterday — the current day is still accumulating.

## Response `200`

Successful Response

- PnlSummaryResponse — Window totals for one shop as a P&L waterfall.
  - `shop_id` integer, required
  - `seller_id` string, required
  - `currency` string, required
  - `start_date` string, required
  - `end_date` string, required
  - `days_with_data` integer, required — Daily rows that contributed to these totals.
  - `totals` PnlWaterfall, required — P&L lines for a window, straight from TikTok's own daily series. Signs are TikTok's: ``gross_sales`` is positive, cost lines are negative. Costs the platform cannot know (COGS, sample cost, creator bonuses, agency fees) are NOT represented here — those arrive with the cost-input layer.
    - `gross_sales` number, required
    - `refunds` number, required
    - `referral_fee` number, required
    - `affiliate` number, required — Affiliate commission, incl. shop-ads commission.
    - `gmv_max` number, required — GMV Max ad cost. Reliable at shop x day only — TikTok ships the per-order column empty, so per-SKU allocation needs GMV Max campaign data instead.
    - `campaigns` number, required
    - `managed_services` number, required
    - `shipping_and_warehousing_cost` number, required
    - `others` number, required
    - `net_earnings` number, required — TikTok's own bottom line for the window.
  - `rollups` object — TikTok's own rollup columns, reported BESIDE the waterfall and deliberately not inside it. `total_marketing_cost` is exactly gmv_max + affiliate + campaigns + managed_services, so adding it as a waterfall line would double-count all four.
  - `data_status` PnlDataStatus, required — Freshness and reachability of this shop's P&L data. ``state`` distinguishes "no sales" from "we cannot read the finance export": ``no_permission`` means the shop's Seller Center account lacks finance-tab access and the fix is customer-side, not a retry.
    - `state` string, required — Latest export-run status: never_run | pending | parsed | empty | failed | no_permission.
    - `last_synced_at` string, nullable — ISO timestamp of the newest successfully parsed run.
    - `last_window` PnlDateWindow — The date window an export run requested.
      - `start_date` string, nullable
      - `end_date` string, nullable

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/reacherapp/apis/reacher-data-api.md) · [All operations](https://skmtc.dev/reacherapp/apis/reacher-data-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/reacherapp/reacher-data-api/revisions/5eefff009b5b/schema)
