Sold Items Report
Retrieve the Sold Items Report by date range, location, customer account, inventory category, and salesperson.
Sold Items Report
GET/api/v3/reports/sold-items
Required scope: reports:read
Requires live report and invoice-list permissions and an accessible account. The authenticated credential determines the SalesBinder account; customer_id means the customer account shown in the report's Account filter. There is no tenant-selection parameter.
Users without all-invoice visibility are restricted to their own invoices, even if another salesperson is requested. Effective filters are returned. Without unit-cost permission, net_cost and profit are omitted from every row and summary, and sorting by either is rejected.
Query parameters
| Parameter | Default | Description |
|---|---|---|
date_from | Today minus 30 days | Inclusive invoice issue date in YYYY-MM-DD format. Supply both dates or omit both. |
date_to | Today | Inclusive invoice issue date, on or after date_from. Must be before date_from plus one year. |
location_id | All locations | Account-owned location UUID. Matches the item's current location or the linked variation-location record, as in the web report; this is not an invoice-location or historical shipping-location filter. |
customer_id | All visible customers | Account-owned customer UUID. |
category_id | All categories | Inventory category UUID, including its subcategories as in the web report. |
user_id | All permitted salespeople | Invoice salesperson UUID; forced to the caller when all-invoice visibility is unavailable. |
group_by | item | item, account, or variation. |
sort | total_qty | item_name, item_number, customer_name, total_qty, net_revenue, net_cost, profit, or last_sold_date. Customer sorting requires account grouping; cost/profit sorting requires unit-cost permission. |
direction | desc | asc or desc. |
page | 1 | Page number, normalized to at least 1. |
limit | 20 | Grouped rows per page, clamped to 1–100. |
include_total | true | Include exact grouped-row counts. Accepts true, false, 1, or 0. |
include_summary | true | Include totals and the top-ten category revenue breakdown for the full filtered report. Accepts the same boolean values. |
Dates use the application calendar with years 1000–9999. A full calendar year, including a leap year, is supported (for example January 1–December 31). Invalid or oversized ranges, unsupported options, malformed UUIDs, and unavailable filter targets return 422 invalid_query_parameter with the offending param. Unknown and other-account filter targets receive the same error.
curl 'https://yourbusiness.salesbinder.com/api/v3/reports/sold-items?date_from=2026-10-01&date_to=2026-10-31&group_by=variation&limit=100' \
--header 'Authorization: Bearer YOUR_API_KEY'Grouping
item: one row per inventory item.account: one row per item/customer combination, not a single combined row per customer. Customer IDs remain available for deleted customers, while their names can be null.variation: one row per item variation, combining surviving variations across locations. Historical attributes are preferred over live values. Orphaned variation-location records and unlinked historical snapshots retain distinct groups rather than merging into ordinary items.
Every row has an opaque id for its grouping identity. It is stable across pagination and filtering while the underlying identity is unchanged. Changing grouping mode or deleting/reassigning a variation association can change the group identity. Sorting uses item ID and the applicable customer/variation identity as tie-breakers.
Response
Returns the standard paginated list envelope with object, url, has_more, data, and pagination, plus effective filters, currency, and currency_decimal_places.
| Row field | Description |
|---|---|
id, object | Opaque group ID and sold_items_group. |
item_id, item_number, item_name, sku | Inventory identity and current item metadata. |
category_id, category_name | Current item category. |
last_sold_date | Latest matching invoice issue date. |
total_qty | Signed quantity as a decimal string, preserving fractional quantities. |
net_revenue | Sales revenue after discounts, excluding tax. |
net_cost, profit | Cost and revenue minus cost; omitted without unit-cost permission. |
customer_id, customer_name | Present only with account grouping. |
variation_id, variation_location_id | Present only with variation grouping. Nullable; location ID is returned only when the group uses exactly one non-null variation-location ID. |
variation_attributes | Variation grouping only: an array of {name, value} strings; empty for groups without readable attributes. |
Money values are decimal strings at the account's report precision (0–4). Quantity strings use up to four decimal places without trailing zeroes. Discounted lines, including fully discounted sales, and signed quantities follow the web report calculations. Services and lines without a surviving inventory item are excluded; cancelled invoices are excluded. No currency conversion occurs.
Summary
When include_summary=true, the response includes:
{
"summary": {
"totals": {
"total_qty": "3.25",
"net_revenue": "32.50",
"net_cost": "13.00",
"profit": "19.50"
},
"top_categories": [],
"category_limit": 10
}
}Totals cover the entire filtered result, not just the current page. top_categories contains up to ten positive-revenue categories, ordered by revenue, with category_id, category_name, net_revenue, and numeric percentage. Percentages use the full signed report revenue as the denominator; they need not sum to 100 and may exceed 100 when other categories have negative revenue. When total revenue is nonpositive, the breakdown is empty. It is not a complete category listing.
Pagination counts refer to grouped rows, not invoice lines or quantity sold. include_total=false omits total_records and total_pages; include_summary=false omits summary. Both options independently skip their corresponding queries. Empty reports return an empty data array and zero totals when requested.
For larger exports, fetch the summary only on the first page. Results can change between requests, and large page offsets still have a cost. Responses use Cache-Control: no-store.