Reports
Read-only sales, product, customer, tax, refund and stock reports, plus the CSV and PDF exports.
Read-only, on their own permission, so a bookkeeper can be given the numbers and nothing else.
Sales summary
/api/v1/kahunacart/reports/summary
Headline figures for a date range: revenue, orders, average order value, items sold, refunds, top products, a breakdown by payment method, and a per-day series carrying revenue, orders, units and refunds. Defaults to the last 30 days, and the range it actually used comes back in the response along with the currency the figures are in. Money is in minor units. A total covers one currency, the base currency unless you pass currency; on a store with orders in other currencies the response also carries other_currencies, a list of {currency, orders} counting what the figures leave out.
Parameters
| Name | Type | Description |
|---|---|---|
| currency_table optional | string |
Include by_currency native revenue, orders and average, with a nullable rated base equivalent and exclusion count
One of:
1 |
| currency_picker optional | string |
Ask for report_currency_available when the store has several currencies or historical foreign orders; no extra field on a single-currency store
One of:
1 |
| currency optional | string | A known currency code for native totals, or all for exact totals in base currency using each order's frozen fx_to_base. Unrated orders and refunds are excluded and counted separately. Left out, the base currency. A single-currency store stays unchanged; an unknown code is a 422. |
| from optional | string | Start of the range as YYYY-MM-DD |
| to optional | string | End of the range as YYYY-MM-DD |
Product sales report
/api/v1/kahunacart/reports/products
What sold in a date range, by product and by variant, sorted by revenue, with units, revenue and refunds on each. totals covers the whole range rather than the page, so a share-of-revenue figure adds up. Money is in minor units.
Parameters
| Name | Type | Description |
|---|---|---|
| currency_picker optional | string |
Ask for report_currency_available when the store has several currencies or historical foreign orders; no extra field on a single-currency store
One of:
1 |
| currency optional | string | A known currency code for native totals, or all for exact totals in base currency using each order's frozen fx_to_base. Unrated orders and refunds are excluded and counted separately. Left out, the base currency. A single-currency store stays unchanged; an unknown code is a 422. |
| from optional | string | Start of the range as YYYY-MM-DD |
| to optional | string | End of the range as YYYY-MM-DD |
| page optional | integer |
At least 1.
Default:
1 |
| sort optional | string |
A column to sort the whole range by before it is paged; leave out for the usual order
One of:
product, units, revenue, refunds, share |
| dir optional | string |
One of:
asc, descDefault:
asc |
| q optional | string | Words to search for in the product title, and the title or SKU of a variant that sold; totals stays the whole range; every word has to be there, in any order. Applied before the sort and the page, and total counts what it found |
Response
Answers {products: [{product_id, title, units, revenue_minor, refunded_minor, variants: [...]}], totals: {products, units, revenue_minor, refunded_minor}}, sorted by revenue.
Customer sales report
/api/v1/kahunacart/reports/customers
Who bought in a date range, sorted by revenue, with each customer's orders, revenue, average order value, first and last order and whether they were new in the range, plus new against returning splits for the whole range. customer_id is null for a guest checkout, which groups by the address given. Money is in minor units, in the currency named on the response (see currency and other_currencies on report_summary).
Parameters
| Name | Type | Description |
|---|---|---|
| currency_picker optional | string |
Ask for report_currency_available when the store has several currencies or historical foreign orders; no extra field on a single-currency store
One of:
1 |
| currency optional | string | A known currency code for native totals, or all for exact totals in base currency using each order's frozen fx_to_base. Unrated orders and refunds are excluded and counted separately. Left out, the base currency. A single-currency store stays unchanged; an unknown code is a 422. |
| from optional | string | Start of the range as YYYY-MM-DD |
| to optional | string | End of the range as YYYY-MM-DD |
| page optional | integer |
At least 1.
Default:
1 |
| sort optional | string |
A column to sort the whole range by before it is paged; leave out for the usual order
One of:
customer, orders, revenue, average, first, last |
| dir optional | string |
One of:
asc, descDefault:
asc |
| q optional | string | Words to search for in the email and the name; totals stays the whole range; every word has to be there, in any order. Applied before the sort and the page, and total counts what it found |
Response
Answers {customers: [{customer_id, email, name, orders, revenue_minor, aov_minor, first_order_at, last_order_at, is_new}], totals: {customers, orders, revenue_minor, aov_minor}, new_customers, returning_customers, new_revenue_minor, returning_revenue_minor}. customer_id is null for a guest checkout.
Tax report
/api/v1/kahunacart/reports/taxes
Tax collected in a date range, per label and rate, with the taxable base and the tax beside it. engine says whether the store is running tax zones or a flat rate and what that rate is, so an empty table can be read as "this store charges no tax" rather than as a failure. Money is in minor units.
Parameters
| Name | Type | Description |
|---|---|---|
| currency_picker optional | string |
Ask for report_currency_available when the store has several currencies or historical foreign orders; no extra field on a single-currency store
One of:
1 |
| currency optional | string | A known currency code for native totals, or all for exact totals in base currency using each order's frozen fx_to_base. Unrated orders and refunds are excluded and counted separately. Left out, the base currency. A single-currency store stays unchanged; an unknown code is a 422. |
| from optional | string | Start of the range as YYYY-MM-DD |
| to optional | string | End of the range as YYYY-MM-DD |
Response
Answers {rows: [{label, rate, included, orders, base_minor, tax_minor}], totals: {orders, base_minor, tax_minor, included_minor}, engine: {zones, flat_rate, flat_label}}. engine says whether the store is running zones or the flat rate, so an empty table can be explained.
Refund report
/api/v1/kahunacart/reports/refunds
Every refund transaction raised in a date range, newest first, whatever became of it, with the order and customer it belongs to. Only the successful ones count toward totals and toward rate_bp, which is the refund rate in basis points so it stays an integer, 250 meaning 2.5 percent, and null when there was no revenue to measure against.
Parameters
| Name | Type | Description |
|---|---|---|
| currency_picker optional | string |
Ask for report_currency_available when the store has several currencies or historical foreign orders; no extra field on a single-currency store
One of:
1 |
| currency optional | string | A known currency code for native totals, or all for exact totals in base currency using each order's frozen fx_to_base. Unrated orders and refunds are excluded and counted separately. Left out, the base currency. A single-currency store stays unchanged; an unknown code is a 422. |
| from optional | string | Start of the range as YYYY-MM-DD |
| to optional | string | End of the range as YYYY-MM-DD |
| page optional | integer |
At least 1.
Default:
1 |
| sort optional | string |
A column to sort the whole range by before it is paged; leave out for the usual order
One of:
raised, order, customer, amount, provider, reason, status |
| dir optional | string |
One of:
asc, descDefault:
asc |
| q optional | string | Words to search for in the order number, the email, the provider, the reason and the provider's reference; totals, attempts and the rate stay the whole range; every word has to be there, in any order. Applied before the sort and the page, and total counts what it found |
Response
Answers {refunds: [{id, created_at, amount_minor, provider, status, reason, reference, order_id, order_number, email, customer_id}], totals: {refunds, refunded_minor}, revenue_minor, rate_bp}, newest first. Every refund is listed whatever became of it, but only successful ones count toward totals and rate_bp. rate_bp is basis points (250 is 2.5%) and null when there was no revenue to measure against.
Low stock report
/api/v1/kahunacart/reports/low-stock
Stock-managed variants at or below a threshold, right now rather than over a range. The default threshold is 5 and 0 asks only for what has actually run out. Variants that do not track stock are never listed.
Parameters
| Name | Type | Description |
|---|---|---|
| threshold optional | integer |
Report variants with this many or fewer on hand
Default:
5 |
Response
Answers {items: [...], threshold}. A threshold of 0 asks only for what has run out; a negative one clamps to zero.
Export the orders report as CSV
/api/v1/kahunacart/reports/export
Download the orders report as CSV over the same filters the report screens take.
Export the orders report as PDF
/api/v1/kahunacart/reports/export.pdf
Download the same report as a PDF, rendered server-side by dompdf.
Report ranges are uncapped. A range over 400 days comes back one row per calendar month rather than one per day, and bucket in the payload says month instead of day. Days up to the rollup watermark are read from a daily rollup rather than scanned; see Reports and the rollup.
All but low-stock take ?from=YYYY-MM-DD&to=YYYY-MM-DD and default to the last 30 days. Every JSON payload repeats from, to and currency so a response can be read without the request beside it.
products, customers and refunds also take ?page= and answer with total, page and per_page; taxes does not, because a store has a handful of tax labels. Their totals block covers the whole range, not the page.