sales

get sales table

A page of sales per variant or per product: gross sales, discounts, returns, taxes, net sales, net items sold, returned units, return rate, sell-through rate, and the units and revenue lost to stockouts, with filtered_max_size for the size of the filtered set. A variant row also carries price_sensitivity, the pricing engine's tier, and price_sensitivity_absence, which says which blank a null tier is; a product row carries neither.

type=variants is the default and type=products aggregates to the product. Page with limit and offset, narrow with filter_args on date, location, sales channel, vendor, collection and custom fields, order with sort_args, and set export=true to receive a download URL instead of rows. comparison_date_gte and comparison_date_lte add the comparison period the change figures are measured against.

metric_columns adds any of the library's metrics to each row: profitability, prices, stock, plan gaps and forecast accuracy. A metric is null where its evidence is missing, never zero, and the row's metric_reasons says why. include_totals=true adds totals over the whole filtered set.

A key issued to one account reads that account's sales only: its rows, totals, shares and comparison figures are measured over that account's orders, and an account_id filter naming another account is refused.

Scope: sales:read.

get/api/v1/sales/table

Request

  • Base URL: https://api.app.tightly.io
  • URL: https://api.app.tightly.io/api/v1/sales/table
  • Auth: HTTP bearer

Query parameters

limitinteger

Pagination limit

offsetinteger

Pagination offset

filter_argsstring
Example:[{"key":"date","operation":"gte","value":"2024-12-01"},{"key":"date","operation":"lte","value":"2024-12-31"},{"key":"missed_revenue","operation":"gte","value":100}]

JSON array of filter conditions. Filter keys: date, sales_channel_id, location_id, variant_id, product_id, net_items_sold, net_items_sold_by_channel, gross_sales, net_sales, total_sales, returned_units, return_rate, sell_through_rate, lost_sales_units, missed_revenue, category, shopify_tags, account_id, door_id, and every library metric in the row schema. Numeric keys support gte/lte. variant_id/product_id/sales_channel_id/location_id/account_id/door_id support eq/in. Example - filter variants with missed revenue >= $100: json [ {"key": "date", "operation": "gte", "value": "2024-12-01"}, {"key": "date", "operation": "lte", "value": "2024-12-31"}, {"key": "missed_revenue", "operation": "gte", "value": 100} ]

sort_argsstring
Example:sales_amount,-variant_title

Comma-separated list of sort arguments (e.g., "+sales_amount,-variant_title"). Valid sort fields: variant_title, product_title, sku, product_id, variant_id, custom_fields, net_items_sold, gross_sales, discounts, returns, net_sales, taxes, total_sales, returned_units, return_rate, sell_through_rate, lost_sales_units, missed_revenue, margin_leak, net_sales_change, net_sales_swing, and every library metric in the row schema. margin_leak is |discounts| + |returns|, what discounting and returns ate of the period. net_sales_change (signed) and net_sales_swing (absolute) measure net sales against the comparison_date_gte/lte window and are NULL without one, so sorting by them then has no effect, always pass the comparison window with these two. Note: custom_fields is sorted lexicographically as text (e.g. "10" sorts before "2"). Never use gross_profit as a sort field. It is not supported and will be silently ignored, causing results to return in default order. Use gross_sales or net_sales to sort by revenue.

searchstring

Search term to filter sales

type'variants' | 'products'

View type - 'variants' shows individual variants, 'products' shows grouped by product.

exportboolean

If true, returns an export URL instead of paginated table data

comparison_date_gtestring date
Example:2023-01-01

Start of comparison date range. On JSON responses it drives the per-row net_sales_change / net_sales_swing columns; on exports it adds side-by-side period columns. Pass both bounds or neither.

comparison_date_ltestring date
Example:2023-12-31

End of comparison date range. See comparison_date_gte.

metric_columnsstring
Example:gross_profit,gross_margin,on_order_units

Comma-separated library metrics to compute on each row, at most 150: any metric field of the row schema, or one of the grid's own columns. An unknown name is refused 400. A metric that is sorted or filtered on is computed without being named here, and a metric that is not computed is served as null.

columnsstring
Example:sku,product_title,net_sales,gross_margin

Exports only. Comma-separated columns the file carries, in this order, at most 150. A library metric named here is computed for the file.

commitment_idstring

A Commitment. Narrows the grid to the products in its scope and supplies the targets sell_through_target, sell_through_gap, margin_target and margin_gap read. An unknown Commitment is refused 400.

plan_snapshot_idstring

A saved product plan. sales_plan, units_plan and their gaps are read against it and are null without one.

forecast_vintage_weekstring date
Example:2026-06-01

The week a forecast was saved, as YYYY-MM-DD. forecast_bias and forecast_wape are measured against it and are null without one. With a plan or forecast metric computed, a week after the selected period is refused 400.

include_totalsboolean

Adds totals, the metrics measured over the whole filtered set rather than the page. Off by default because it is a second pass over the filtered set. Exports never carry totals.

age_daysinteger

The age in days at which stock counts as aged for aged_stock_units, aged_stock_cost and aged_stock_share.

Headers

Tightly-Versionstring
Example:2026-11

The date train to answer on. One train exists today, 2026-11, the one this reference describes and the one every key is minted on, so the call answers on it with or without this header. Send it anyway, so a client built now names its train from the start.

Response

The sales table, or an export url

messageobject

severity, service and desc.

Changes

No recorded changes to this operation across all 1 revision of this API.