Home Integration API reference
REST API for integrations and external apps
Data & Analytics
All report endpoints below use GET with integration API authentication under /api/v1/integration/reports/*. Unless noted otherwise, format=csv streams a UTF-8 BOM download, pagination is ignored for CSV exports, a non-empty q must be at least 2 characters, and any supplied location_id must belong to the business; unknown ids return 404 and out-of-scope ids return 403.
Returns profit and loss figures for a resolved date range using the same calculation pipeline as the web report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/profit-loss |
| Permission | profit_loss_report.view. |
| Default range | The current financial year when start_date and end_date are omitted. |
| Breakdown filter | q filters total_sell_by_subtype, module rows, and gross_profit_label, but it does not change the headline numeric totals. |
| CSV behavior | format=csv downloads section/field/value rows for the resolved range. |
| Success response | 200 with the full profit/loss payload. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id | integer | No | Optional business-location filter. |
user_id | integer | No | Optional business user filter. Invalid ids return 422. |
q | string | No | Filters subtype/module breakdowns by label or numeric id-like values without changing the summary totals. |
ProfitLossBreakdownRow object| Field | Type | Description |
|---|---|---|
sub_type | string | null | Sell subtype label or null for normal sells. |
total_before_tax | number | Subtotal before tax for that subtype. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.user_id, data.q | mixed | Echoes the resolved filters. |
Headline totals such as opening_stock, closing_stock, total_purchase, total_sell, total_expense, gross_profit, and net_profit | number | Main profit/loss figures from TransactionUtil::getProfitLossDetails(). |
data.total_sell_by_subtype | array<ProfitLossBreakdownRow> | Sales grouped by subtype. |
data.left_side_module_data, data.right_side_module_data | array<object> | Optional module hook rows with label/value pairs. |
data.gross_profit_label | array<string> | Localized gross-profit explanation strings. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report was generated successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks profit_loss_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, q is too short, or user_id is invalid. | Laravel validation JSON or { "message": string }. |
500 | The backend profit/loss calculation threw an exception. | { "message": "Could not compute profit and loss" } |
Returns the same purchase-versus-sale summary cards used by the web Purchase & Sale report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/purchase-sell |
| Permission | purchase_n_sell_report.view. |
| Default range | The current calendar month when dates are omitted. |
q behavior | The query is validated and echoed as data.q, but it does not change any totals. |
| CSV behavior | format=csv downloads flattened section/field/value rows. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id | integer | No | Optional location filter. |
q | string | No | Echo-only search term. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.q | mixed | Echoes the resolved filters. |
data.purchase | object | Purchase totals: inclusive/exclusive tax, due amount, shipping, and additional expense. |
data.sell | object | Sell totals: inclusive/exclusive tax, invoice due, shipping, and additional expense. |
data.total_purchase_return_inc_tax, data.total_sell_return_inc_tax | number | Inclusive-tax return totals. |
data.difference.total, data.difference.due | number | The same summary formulas shown in the web report. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The summary was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks purchase_n_sell_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, or q is too short. | Laravel validation JSON or { "message": string }. |
Returns input, output, expense, and module output tax totals using the same summary logic as the web Tax report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/tax-report |
| Permission | tax_report.view. |
| Default range | The current calendar month when dates are omitted. |
| Module output tax | Additional module tax comes from ModuleUtil::getModuleData('getModuleOutputTax'). |
q behavior | Filters by_tax_rate rows and recomputes section totals and totals.tax_difference; module output tax is left unchanged. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id | integer | No | Optional location filter. |
contact_id | integer | No | Optional contact filter. Invalid ids return 422. |
q | string | No | Matches tax names, numeric tax ids, and grouped sub-tax names/ids. |
TaxBreakdownRow object| Field | Type | Description |
|---|---|---|
tax_id, tax_name | integer | string | The matched tax rate identity. |
tax_amount | number | Amount attributed to the rate or grouped tax. |
is_tax_group | boolean | Whether the row represents a grouped tax. |
group_tax_details | array<object> | null | Sub-tax breakdown when is_tax_group is true. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.contact_id, data.q | mixed | Echoes the resolved filters. |
data.input_tax, data.output_tax, data.expense_tax | object | Each section contains total_tax and by_tax_rate. |
data.module_output_tax | object | Contains by_module and total. |
data.totals | object | Contains total_output_tax_including_modules and tax_difference. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The tax report was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks tax_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, contact_id is invalid, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The tax helper pipeline threw an exception. | { "message": "Could not compute tax report" } |
Lists supplier/customer balance-style rows using the same aggregates and due formula as the web Supplier & Customer report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/customer-supplier |
| Permission | contacts_report.view. |
| Date behavior | When both dates are omitted, the report runs across all transaction dates. |
| Text filters | Supports q or legacy search. The resolved text value is returned as data.search and meta.q. |
| Row scope | The underlying query joins transactions, so only contacts with at least one matching transaction appear. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together when either is used. |
location_id, contact_id, customer_group_id | integer | No | Optional location/contact/group filters. Invalid contact or group ids return 422. |
contact_type | string | No | customer or supplier. The controller also includes contacts with type both. |
q, search | string | No | Matches contact name, supplier business name, or numeric contact id. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
CustomerSupplierReportRow object| Field | Type | Description |
|---|---|---|
id, name, name_only, supplier_business_name, contact_type | mixed | Contact identity and display fields. |
total_purchase, total_purchase_return, total_invoice, total_sell_return | number | Purchase/sell movement totals. |
purchase_paid, invoice_received, sell_return_paid, purchase_return_received | number | Payment totals. |
opening_balance, opening_balance_paid, opening_balance_due | number | Opening-balance figures. |
total_ledger_discount_sell, total_ledger_discount_purchase, due | number | Ledger-discount totals and the final computed due amount. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.contact_id, data.customer_group_id, data.contact_type, data.search | mixed | Echoes the applied filters. |
data.contacts | array<CustomerSupplierReportRow> | The current page of matching contacts. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata and the resolved text filter. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks contacts_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, q is too short, or a contact/group filter is invalid. | Laravel validation JSON or { "message": string }. |
Aggregates final sell totals by customer group using the same query as the web Customer Groups report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/customer-group |
| Permission | contacts_report.view. |
| Date behavior | When both dates are omitted, the report runs across all final sells. |
| Ungrouped sales | Sales with no customer group still appear as one row with customer_group_id = null. |
| CSV behavior | Downloads customer_group_id, name, and total_sell. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together when either is used. |
location_id | integer | No | Optional location filter. |
customer_group_id | integer | No | Optional single-group filter. Invalid ids return 422. |
q | string | No | Matches group name text or an exact numeric customer_group_id. |
CustomerGroupReportRow object| Field | Type | Description |
|---|---|---|
customer_group_id | integer | null | Group id or null for ungrouped sales. |
name | string | null | Group name when the group exists. |
total_sell | number | Final sell total for the group. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.customer_group_id, data.q | mixed | Echoes the applied filters. |
data.groups | array<CustomerGroupReportRow> | All matching group aggregates. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The grouped totals were returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks contacts_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, q is too short, or customer_group_id is invalid. | Laravel validation JSON or { "message": string }. |
Lists quantity-on-hand rows by variation and location using the same stock query as the web Stock report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/stock-on-hand |
| Permission | stock_report.view. |
| Data source | ProductUtil::getProductStockDetails(). |
| Manufacturing column | total_mfg_stock only appears when Manufacturing is installed and the subscription/user permissions allow it. |
| Price visibility | unit_price needs access_default_selling_price; stock_price and potential_profit need view_purchase_price. |
| Parameter | Type | Required | Description |
|---|---|---|---|
location_id | integer | No | Optional location filter. |
category_id, sub_category_id, brand_id, unit_id, product_id, repair_model_id | integer | No | Optional business-scoped filters. Invalid ids fail validation. |
tax_id | integer | No | Optional tax-rate filter. |
type, active_state | string | No | type accepts single or variable. active_state accepts active or inactive. |
only_mfg_products, not_for_selling | boolean | No | Optional boolean filters. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches product, SKU, variation, location, or numeric product/variation ids. |
StockOnHandReportRow object| Field | Type | Description |
|---|---|---|
product_id, variation_id, location_id, location_name | mixed | Product/variation/location identity. |
product, sku, variation, type, unit, category_name | mixed | Main descriptive fields. |
enable_stock, stock, alert_quantity | mixed | Stock status and alert figures. stock is null when stock tracking is disabled. |
total_sold, total_transfered, total_adjusted | number | Movement totals for the row. |
unit_price, stock_price, stock_value_by_sale_price, potential_profit | number | null | Price/value fields gated by selling-price or purchase-price permissions. |
total_mfg_stock | number | null | Manufacturing-only stock figure when enabled. |
product_custom_field1 ... product_custom_field4 | string | null | Configured custom product fields. |
| Field | Type | Description |
|---|---|---|
data.location_id | integer | null | Echoes the optional location filter. |
data.filters | object | Echoes all other filters, including include_manufacturing and q. |
data.items | array<StockOnHandReportRow> | The current page of stock rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata and the resolved search term. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The stock rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks stock_report.view. | { "message": "Unauthorized" } |
422 | A filter failed validation or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The stock query failed unexpectedly. | { "message": "Could not load stock report" } |
Lists purchase-line stock that still has remaining quantity, with expiry-date and lot details matching the web Stock Expiry report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/stock-expiry |
| Permission | stock_report.view. |
| Row scope | Only purchase lines with stock left greater than zero are returned. |
| Date filter | exp_date_filter restricts rows to exp_date <= filter. |
| CSV behavior | Filenames are stock-expiry-all.csv or stock-expiry-until-{date}.csv. |
| Parameter | Type | Required | Description |
|---|---|---|---|
location_id | integer | No | Optional location filter. |
category_id, sub_category_id, brand_id, unit_id | integer | No | Optional business-scoped product filters. |
exp_date_filter | string | No | Business-format date normalized before comparison. |
only_mfg_products | boolean | No | Restricts rows to production-purchase stock only. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches product, SKU, variation, location, lot, purchase ref, or numeric ids. |
StockExpiryReportRow object| Field | Type | Description |
|---|---|---|
product, product_display, sku, product_type, variation, sub_sku, product_variation | mixed | Product identity fields. |
location, location_id | mixed | Location details. |
mfg_date, exp_date, is_expired | mixed | Manufacturing/expiry dates and the computed expiry flag. |
unit, stock_left | mixed | Remaining quantity and unit. |
ref_no, transaction_id, purchase_line_id, lot_number | mixed | Source purchase and lot identifiers. |
| Field | Type | Description |
|---|---|---|
data.location_id, data.exp_date_filter, data.only_mfg_products, data.q | mixed | Echoes the resolved filters. |
data.items | array<StockExpiryReportRow> | The current page of expiry rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The expiry rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks stock_report.view. | { "message": "Unauthorized" } |
422 | A filter failed validation or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The expiry query failed unexpectedly. | { "message": "Could not load stock expiry report" } |
Returns remaining stock by lot/batch using the same stock math as the web Lot report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/lot-report |
| Permission | stock_report.view. |
| Row scope | Only purchase lines with a non-null lot_number are included. |
| Inventory math | stock, total_sold, and total_adjusted follow the same correlated purchase-allocation logic as the web report. |
| CSV behavior | format=csv downloads lot-report-all.csv. |
| Parameter | Type | Required | Description |
|---|---|---|---|
location_id | integer | No | Optional location filter. |
category_id, sub_category_id, brand_id, unit_id | integer | No | Optional business-scoped product filters. |
only_mfg_products | boolean | No | Restricts rows to production-purchase stock only. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches product, SKU, variation, lot number, or numeric product/variation ids. |
LotReportRow object| Field | Type | Description |
|---|---|---|
product, product_display, variation_name, sub_sku, product_type | mixed | Product and variation identifiers. |
lot_number, exp_date, is_expired | mixed | Lot and expiry metadata. |
stock, total_sold, total_adjusted, unit | mixed | Remaining quantity and movement totals. |
| Field | Type | Description |
|---|---|---|
data.location_id, data.only_mfg_products, data.q | mixed | Echoes the resolved filters. |
data.items | array<LotReportRow> | The current page of lot rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The lot rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks stock_report.view. | { "message": "Unauthorized" } |
422 | A filter failed validation or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The lot report query failed unexpectedly. | { "message": "Could not load lot report" } |
Combines the stock-adjustment summary totals with a paginated adjustment list, matching the current web report split.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/stock-adjustment-report |
| Primary permission | stock_report.view. |
| Secondary row permission | List rows only render when the token user has stock_adjustment.view, stock_adjustment.create, or view_own_stock_adjustment. |
| Summary behavior | data.summary is returned even when list rows are omitted. When the user only has view_own_stock_adjustment, the row query is user-scoped but the summary remains aggregate. |
| Price visibility | final_total and total_amount_recovered are null without view_purchase_price. |
| CSV behavior | Exports only adjustment rows, never the summary. If rows are not visible, the CSV contains headers only. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id | integer | No | Optional location filter. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches reference numbers, location names, product fields, or numeric adjustment/line ids. |
StockAdjustmentReportSummary object| Field | Type | Description |
|---|---|---|
total_amount, total_recovered, total_normal, total_abnormal | number | Summary totals from the stock adjustment report cards. |
StockAdjustmentReportRow object| Field | Type | Description |
|---|---|---|
id, transaction_date, ref_no | mixed | Adjustment identity fields. |
location_name, added_by | string | null | Display fields for the location and creator. |
adjustment_type, adjustment_type_label | mixed | Stored adjustment type and its translated label. |
final_total, total_amount_recovered | number | null | Cost/recovered amounts, hidden when purchase-price visibility is not allowed. |
additional_notes | string | null | Saved notes for the adjustment. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.q | mixed | Echoes the resolved filters. |
data.summary | StockAdjustmentReportSummary | Aggregate stock-adjustment totals. |
data.items | array<StockAdjustmentReportRow> | Visible list rows. May be empty when the user lacks secondary list permissions. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q, meta.items_included | mixed | Pagination metadata plus a flag showing whether row data was included. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report summary was returned successfully, with rows included when allowed. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks stock_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The summary query or row query failed unexpectedly. | { "message": string } |
Returns the top-selling products by units sold using the same logic as the web Trending Products report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/trending-products |
| Permission | trending_product_report.view. |
| Data source | ProductUtil::getTrendingProducts(). |
| Date behavior | When dates are omitted, no date filter is applied. When limit is omitted, the util defaults to the top 5 products. |
| Success response | 200 with one summary object containing the returned items and total_units_sold. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id | integer | No | Optional location filter. |
category_id, sub_category_id, brand_id, unit_id | integer | No | Optional business-scoped product filters. |
product_type | string | No | single, variable, or combo. |
limit | integer | No | Maximum rows to return, from 1 to 100. |
q | string | No | Matches product name, SKU, unit short name, or a numeric product id. |
TrendingProductsReportRow object| Field | Type | Description |
|---|---|---|
product, sku, unit | mixed | Product identity fields. |
total_unit_sold | number | Total units sold for the product, net of returns. |
label | string | Prebuilt chart/display label in the form name - sku (unit). |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.category_id, data.sub_category_id, data.brand_id, data.unit_id, data.product_type, data.limit, data.q | mixed | Echoes the applied filters. |
data.total_units_sold | number | Sum of total_unit_sold across the returned items. |
data.items | array<TrendingProductsReportRow> | The returned trending product rows. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks trending_product_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The trending-products query failed unexpectedly. | { "message": "Could not load trending products" } |
Returns purchase-to-sell or purchase-to-stock-adjustment mapping rows using the same source query as the web Items report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/items-report |
| Permission | purchase_n_sell_report.view. |
| Source query | transaction_sell_lines_purchase_lines joined to purchase lines, sell lines, and stock adjustment lines. |
| Date behavior | purchase_start/purchase_end and sale_start/sale_end are independent pairs. The sale range matches either the sell date or the stock adjustment date. |
| Price visibility | purchase_price, selling_unit_price, and subtotal are null without view_purchase_price. |
| Parameter | Type | Required | Description |
|---|---|---|---|
purchase_start, purchase_end | string | Conditional | Business-format purchase-date range. Both must be sent together and purchase_start must not be after purchase_end. |
sale_start, sale_end | string | Conditional | Business-format sale/adjustment date range. Both must be sent together and sale_start must not be after sale_end. |
supplier_id, customer_id, location_id | integer | No | Optional supplier, customer, and location filters. |
only_mfg_products | boolean | No | Restricts rows to production_purchase rows. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches product fields, contacts, refs, invoice numbers, location, lot, sell line note, or numeric ids. |
ItemsReportRow object| Field | Type | Description |
|---|---|---|
sku, product_name, product_display, product_type, sell_line_note | mixed | Product and line-description fields. |
purchase_date, purchase_ref_no, purchase_type, purchase_id, is_opening_stock_purchase, lot_number | mixed | Purchase-side fields. |
supplier, supplier_business_name, supplier_display | mixed | Supplier fields. |
purchase_price | number | null | Purchase price per unit when purchase-price access is allowed. |
sell_date, sale_invoice_no, stock_adjustment_ref_no, is_stock_adjustment | mixed | Sell-side or stock-adjustment-side linkage fields. |
customer, customer_business_name, customer_display, location | mixed | Customer and location fields. |
quantity, qty_returned, unit, selling_unit_price, subtotal | mixed | Movement and amount fields, with pricing gated by view_purchase_price. |
| Field | Type | Description |
|---|---|---|
data.purchase_start, data.purchase_end, data.sale_start, data.sale_end, data.supplier_id, data.customer_id, data.location_id, data.only_mfg_products, data.q | mixed | Echoes the resolved filters. |
data.items | array<ItemsReportRow> | The current page of mapping rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks purchase_n_sell_report.view. | { "message": "Unauthorized" } |
422 | A date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The items-report query failed unexpectedly. | { "message": "Could not load items report" } |
Lists grouped purchase-line rows using the same query as the web Product Purchase report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/product-purchase-report |
| Permission | purchase_n_sell_report.view. |
| Date behavior | When dates are omitted, the report runs across all purchase transactions. |
| Variation lookup | variation_id must belong to a product in the business; otherwise the endpoint returns 404. |
| Price visibility | unit_purchase_price and subtotal are null without view_purchase_price. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
variation_id, location_id, supplier_id, brand_id | integer | No | Optional variation, location, supplier, and brand filters. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches product fields, supplier fields, purchase ref, or numeric transaction/purchase-line ids. |
ProductPurchaseReportRow object| Field | Type | Description |
|---|---|---|
purchase_line_id, transaction_id, ref_no, transaction_date | mixed | Purchase-line and transaction identity fields. |
product_name, product_display, product_type, sub_sku | mixed | Product identity fields. |
supplier, supplier_business_name, supplier_display | mixed | Supplier fields. |
purchase_qty, quantity_adjusted, unit | mixed | Quantity and unit fields. |
unit_purchase_price, subtotal | number | null | Amount fields gated by view_purchase_price. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.variation_id, data.location_id, data.supplier_id, data.brand_id, data.q | mixed | Echoes the applied filters. |
data.items | array<ProductPurchaseReportRow> | The current page of grouped purchase-line rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks purchase_n_sell_report.view. | { "message": "Unauthorized" } |
404 | variation_id does not belong to a product in the business. | { "message": "Variation not found" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The product-purchase query failed unexpectedly. | { "message": "Could not load product purchase report" } |
Returns final sell-line rows using the same detailed query as the web Product Sell report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/product-sell-report |
| Permission | purchase_n_sell_report.view. |
| Row scope | Only final sells and top-level sell lines (parent_sell_line_id = null) are returned. |
| Variation lookup | variation_id must belong to a business product; invalid ids return 404. |
| Price visibility | unit_price, discount_amount, item_tax, unit_sale_price, and subtotal are null without access_default_selling_price. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
variation_id, location_id, customer_id, customer_group_id, category_id, brand_id | integer | No | Optional filters for the sell lines returned. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches product fields, customer fields, invoice numbers, POS contact ids, or numeric sell/sell-line ids. |
ProductSellReportRow object| Field | Type | Description |
|---|---|---|
sell_line_id, transaction_id, invoice_no, transaction_date | mixed | Sell-line and transaction identity fields. |
product_name, product_display, product_type, product_custom_field1, product_custom_field2, sub_sku | mixed | Product identity fields. |
customer, supplier_business_name, customer_display, contact_id, contact_no, contact_email | mixed | Customer fields. |
sell_qty, unit | mixed | Quantity and unit fields. |
unit_price, discount_type, discount_amount, discount_display, tax_name, item_tax, unit_sale_price, subtotal | mixed | Price and tax fields, gated by selling-price visibility. |
payment_methods | string | null | Single payment-method label, multi-pay label, or null. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.variation_id, data.location_id, data.customer_id, data.customer_group_id, data.category_id, data.brand_id, data.q | mixed | Echoes the applied filters. |
data.items | array<ProductSellReportRow> | The current page of sell-line rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks purchase_n_sell_report.view. | { "message": "Unauthorized" } |
404 | variation_id does not belong to a product in the business. | { "message": "Variation not found" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The product-sell query failed unexpectedly. | { "message": "Could not load product sell report" } |
Lists purchase and supplier opening-balance payments using the same payment query as the web Purchase Payment report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/purchase-payment-report |
| Permission | purchase_n_sell_report.view. |
| Payment scope | Includes purchase and supplier opening-balance payments, including split/child-payment relationships through the same EXISTS branch used by the web report. |
| Root-payment rule | When location_id is omitted, the main branch only includes rows where parent_id IS NULL. |
| CSV behavior | Exports all matching payments and ignores pagination. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format payment-date range. Both must be sent together and start_date must not be after end_date. |
location_id, supplier_id | integer | No | Optional location and supplier filters. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches supplier display text, payment ref, purchase ref, method, cheque/card/bank/custom transaction fields, or numeric ids. |
PurchasePaymentReportRow object| Field | Type | Description |
|---|---|---|
payment_id, payment_ref_no, paid_on, amount | mixed | Payment identity and amount fields. |
method, method_label, method_detail | mixed | Stored payment method, resolved label, and detail string for cheque/card/bank/custom rows. |
supplier_display, purchase_ref_no, transaction_id | mixed | Supplier and linked purchase fields. |
cheque_number, card_transaction_number, bank_account_number, custom_transaction_no | string | null | Method-specific stored references. |
document, document_url | string | null | Stored filename and resolved document URL when present. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.supplier_id, data.q | mixed | Echoes the applied filters. |
data.items | array<PurchasePaymentReportRow> | The current page of payment rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The payment rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks purchase_n_sell_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The purchase-payment query failed unexpectedly. | { "message": "Could not load purchase payment report" } |
Lists sell and customer opening-balance payments using the same payment query as the web Sell Payment report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/sell-payment-report |
| Permission | purchase_n_sell_report.view. |
| Payment scope | Includes sell and customer opening-balance payments, with the same split/child-payment logic as the web report. |
| Root-payment rule | When location_id is omitted, the main branch only includes rows where parent_id IS NULL. |
| Return handling | amount is negated when is_return = true, and method_detail appends the translated change-return label. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format payment-date range. Both must be sent together and start_date must not be after end_date. |
location_id, customer_id, customer_group_id | integer | No | Optional location, customer, and customer-group filters. |
payment_types | string | No | Exact payment-method key filter applied to transaction_payments.method. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches customer display text, contact fields, invoice number, payment ref, customer group name, method, transaction fields, or numeric ids. |
SellPaymentReportRow object| Field | Type | Description |
|---|---|---|
payment_id, payment_ref_no, paid_on, amount, is_return | mixed | Payment identity and signed amount fields. |
method, method_label, method_detail | mixed | Stored method, resolved label, and detail string. |
customer_display, contact_id, customer_group, invoice_no, transaction_id | mixed | Customer and linked sell fields. |
cheque_number, card_transaction_number, bank_account_number, custom_transaction_no | string | null | Method-specific stored references. |
document, document_url | string | null | Stored filename and resolved document URL when present. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.customer_id, data.customer_group_id, data.payment_types, data.q | mixed | Echoes the applied filters. |
data.items | array<SellPaymentReportRow> | The current page of payment rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The payment rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks purchase_n_sell_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The sell-payment query failed unexpectedly. | { "message": "Could not load sell payment report" } |
Returns expense totals by category using the same aggregation as the web Expense report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/expense-report |
| Permission | expense_report.view. |
| Default range | The current calendar month when dates are omitted. |
| Totals | expense_refund amounts are subtracted from normal expense totals. |
q behavior | Filters returned category rows; grand_total and chart are recomputed from the filtered items. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id | integer | No | Optional location filter. |
expense_category_id | integer | No | Optional single-category filter. |
q | string | No | Matches category label/name text or an exact numeric expense_category_id. |
ExpenseReportRow object| Field | Type | Description |
|---|---|---|
expense_category_id | integer | null | Category id or null for the "others" bucket. |
category_name | string | null | Stored category name when present. |
category_label | string | Display label, including the translated "others" label for uncategorized rows. |
total_expense | number | Net total for the category after subtracting refunds. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.expense_category_id, data.q | mixed | Echoes the resolved filters. |
data.grand_total | number | Sum of total_expense across the current items set. |
data.items | array<ExpenseReportRow> | The category totals returned by the report. |
data.chart.labels, data.chart.values | array | Chart-ready arrays based on the filtered item list. JSON only. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The expense report was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks expense_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The expense-report query failed unexpectedly. | { "message": "Could not load expense report" } |
Lists cash-register sessions with payment totals by method using the same engine as the web Register report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/register-report |
| Permission | register_report.view. |
| Data source | TransactionUtil::registerReport(). |
| Date behavior | When dates are omitted, no register-created date filter is applied. |
| JSON-only field | data.payment_method_labels is included in JSON responses only and maps payment keys to labels. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id, user_id | integer | No | Optional location and register-user filters. |
status | string | No | open or close. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches location names, user names/emails, or numeric cash-register/user ids. |
RegisterReportRow object| Field | Type | Description |
|---|---|---|
cash_register_id, status, location_id, location_name, user_id, user_display | mixed | Register identity and display fields. |
created_at, closed_at | string | null | Open/close timestamps. closed_at is only populated for closed sessions. |
total_card_slips, total_cheques | integer | Slip/cheque counts recorded on the session. |
total_cash_payment, total_cheque_payment, total_card_payment, total_bank_transfer_payment, total_other_payment, total_advance_payment, total_custom_pay_1 ... total_custom_pay_7 | number | Payment totals by method. |
payments_total | number | Total of all payment columns for the session. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.user_id, data.status, data.q | mixed | Echoes the applied filters. |
data.payment_method_labels | object | Map of payment method keys to display labels. |
data.items | array<RegisterReportRow> | The current page of register sessions. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The register rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks register_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The register-report query failed unexpectedly. | { "message": "Could not load register report" } |
Returns the sales representative summary cards used by the web report: expense totals, sell totals, and optional commission calculations.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/sales-representative |
| Permission | sales_representative.view. |
| Default range | The current calendar month when dates are omitted. |
| Commission behavior | data.commission is only populated when user_id is supplied. The base figure is controlled by POS setting cmmsn_calculation_type (invoice_value or payment_received). |
q behavior | Validated and echoed in data.q only. It does not change totals. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id, user_id | integer | No | Optional location and representative filters. |
q | string | No | Echo-only search term. |
SalesRepresentativeCommission object| Field | Type | Description |
|---|---|---|
commission_percentage | number | The saved commission percentage on the selected user. |
total_payment_with_commission | number | null | The commission base when POS settings use payment received. |
total_sales_with_commission | number | null | The commission base when POS settings use invoice value. |
total_commission | number | Calculated commission amount for the chosen base. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.user_id, data.q | mixed | Echoes the resolved filters. |
data.commission_calculation_type, data.payments_with_commission_tab_enabled | mixed | Derived from the business POS settings. |
data.expense.total_expense | number | Total expense attributed to the selected representative and filters. |
data.sales.total_sell_exc_tax, data.sales.total_sell_return_exc_tax, data.sales.total_sell | number | Sell totals used by the report cards. |
data.commission | SalesRepresentativeCommission | null | Commission details when user_id is supplied. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The summary was returned successfully. | { "data": { ... } } or single-row CSV download. |
403 | The token user lacks sales_representative.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, user_id is invalid, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The sales-representative calculation failed unexpectedly. | { "message": "Could not load sales representative report" } |
Aggregates final sell totals by restaurant table using the same query as the web Table report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/table-report |
| Permission | purchase_n_sell_report.view. |
| Row scope | Only tables attached to final sell transactions appear. |
| Date behavior | When dates are omitted, no date filter is applied. |
| CSV behavior | Exports all matching tables and ignores pagination. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id | integer | No | Optional location filter. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches the restaurant table name or an exact numeric res_table_id. |
TableReportRow object| Field | Type | Description |
|---|---|---|
res_table_id | integer | Restaurant table id. |
name | string | Restaurant table name. |
total_sell | number | Final sell total aggregated for the table. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.q | mixed | Echoes the applied filters. |
data.items | array<TableReportRow> | The current page of aggregated table rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The table rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks purchase_n_sell_report.view. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The table-report query failed unexpectedly. | { "message": "Could not load table report" } |
Returns either invoice-level service-staff orders or line-level service-staff line orders, matching the two web report datasets.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/service-staff-report |
| Permission | sales_representative.view. |
| Required dataset | dataset=orders for invoice-level rows or dataset=line_orders for sell-line rows. |
| Date behavior | orders uses start-of-day/end-of-day datetime filtering; line_orders filters by calendar dates on the sell transaction. |
| CSV behavior | Exports all matching rows for the selected dataset and ignores pagination. |
| Parameter | Type | Required | Description |
|---|---|---|---|
dataset | string | Yes | orders or line_orders. |
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id, service_staff_id | integer | No | Optional location and service-staff filters. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches invoice/location/staff text for orders, or product/invoice/location/staff text for line_orders, plus numeric ids. |
ServiceStaffOrderRow object| Field | Type | Description |
|---|---|---|
transaction_id, transaction_date, invoice_no | mixed | Sell transaction identity fields. |
res_waiter_id, waiter_display, business_location | mixed | Assigned waiter and location fields. |
total_before_tax, discount_amount, tax_amount, final_total | number | Invoice-level totals for the order. |
ServiceStaffLineOrderRow object| Field | Type | Description |
|---|---|---|
sell_line_id, transaction_id, transaction_date, invoice_no | mixed | Sell-line identity fields. |
business_location, res_service_staff_id, service_staff_display | mixed | Assigned staff and location fields. |
product_label, quantity, unit | mixed | Line item identity fields. |
unit_price_before_discount, line_discount_amount, line_discount_type, item_tax, unit_price_inc_tax, line_total | mixed | Pricing and tax fields for the sell line. |
| Field | Type | Description |
|---|---|---|
data.dataset, data.start_date, data.end_date, data.location_id, data.service_staff_id, data.q | mixed | Echoes the applied filters. |
data.items | array<ServiceStaffOrderRow | ServiceStaffLineOrderRow> | The current page of rows for the selected dataset. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The selected dataset was returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks sales_representative.view. | { "message": "Unauthorized" } |
422 | dataset is missing or invalid, a date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The service-staff query failed unexpectedly. | { "message": "Could not load service staff report" } |
Returns India GST sales lines with dynamic per-tax columns, using the same line-level query as the web GST sales report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/gst-sales-report |
| Permission | tax_report.view. |
| Feature flag | config('constants.enable_gst_report_india') must be enabled. |
| Row scope | Only final sells and top-level sell lines (parent_sell_line_id = null) are included. |
| Dynamic columns | Each row includes tax_{id} keys for every non-group tax rate returned in data.tax_columns. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id, customer_id | integer | No | Optional location and customer filters. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches customer fields, invoice number, product fields, HSN short code, or numeric transaction/sell-line ids. |
GstTaxColumn object| Field | Type | Description |
|---|---|---|
id | integer | Non-group tax rate id. |
name | string | Tax rate name. |
amount | number | null | Configured tax percentage for the rate. |
GstSalesReportRow object| Field | Type | Description |
|---|---|---|
sell_line_id, transaction_id, transaction_date, invoice_no | mixed | Sell-line and invoice identity fields. |
customer_display, contact_number, customer_tax_number | mixed | Customer identity fields. |
hsn_short_code, quantity, unit | mixed | Product/GST classification and quantity fields. |
unit_price_before_discount, unit_price_after_discount, discount_amount, discount_type, taxable_value, tax_percent, is_tax_group, item_tax, line_total | mixed | Base pricing and GST fields. |
tax_{id} | number | Per-rate GST amount for each entry in data.tax_columns. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.customer_id, data.q | mixed | Echoes the applied filters. |
data.tax_columns | array<GstTaxColumn> | Defines the dynamic tax_{id} columns used in each row. |
data.items | array<GstSalesReportRow> | The current page of GST sales rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The GST sales rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks tax_report.view or India GST reporting is disabled. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The GST sales query failed unexpectedly. | { "message": "Could not load GST sales report" } |
Returns India GST purchase lines with dynamic per-tax columns, using the same line-level query as the web GST purchase report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/gst-purchase-report |
| Permission | tax_report.view. |
| Feature flag | config('constants.enable_gst_report_india') must be enabled. |
| Row scope | Only purchase lines on received purchases are included. |
| Dynamic columns | Each row includes tax_{id} keys for every non-group tax rate returned in data.tax_columns. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id, supplier_id | integer | No | Optional location and supplier filters. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches supplier fields, purchase ref, product fields, HSN short code, or numeric transaction/purchase-line ids. |
GstPurchaseReportRow object| Field | Type | Description |
|---|---|---|
purchase_line_id, transaction_id, transaction_date, ref_no | mixed | Purchase-line and transaction identity fields. |
supplier_display, contact_number, supplier_tax_number | mixed | Supplier identity fields. |
hsn_short_code, quantity, unit | mixed | Product/GST classification and quantity fields. |
unit_price_before_discount, unit_price_after_discount, discount_amount, taxable_value, tax_percent, is_tax_group, item_tax, line_total | mixed | Base pricing and GST fields. |
tax_{id} | number | Per-rate GST amount for each entry in data.tax_columns. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.supplier_id, data.q | mixed | Echoes the applied filters. |
data.tax_columns | array<GstTaxColumn> | Defines the dynamic tax_{id} columns used in each row. |
data.items | array<GstPurchaseReportRow> | The current page of GST purchase rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The GST purchase rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks tax_report.view or India GST reporting is disabled. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The GST purchase query failed unexpectedly. | { "message": "Could not load GST purchase report" } |
Returns the regional purchase report 606 rows using the same transaction-level query as the web report when the feature is enabled.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/purchase-report-606 |
| Permission | At least one of purchase.view, purchase.create, or view_own_purchase. |
| Feature flag | config('constants.show_report_606') must be enabled. |
| Own-only behavior | When the user lacks purchase.view but has view_own_purchase, rows are restricted to purchases created by that user. |
| Payment method label | Built from linked payment lines: a single label, the translated multi-pay label, or null. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
location_id, supplier_id | integer | No | Optional location and supplier filters. |
payment_status | string | No | paid, due, partial, or overdue. overdue uses the same pay-term SQL logic as the web report. |
status | string | No | Purchase status key from ProductUtil::orderStatuses(). |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches purchase ref, supplier fields, location name, or an exact numeric transaction id. |
PurchaseReport606Row object| Field | Type | Description |
|---|---|---|
transaction_id, ref_no | mixed | Purchase identity fields. |
supplier_name, contact_number | string | null | Supplier display fields. |
total_before_tax, discount_amount, tax_amount, final_total | number | Main purchase totals. |
purchase_year_month, purchase_day | string | null | Purchase date split into regional report columns. |
payment_year_month, payment_day | string | null | Derived from the first payment line when one exists. |
payment_method | string | null | Resolved payment method label. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.supplier_id, data.payment_status, data.status, data.q | mixed | Echoes the applied filters. |
data.items | array<PurchaseReport606Row> | The current page of regional purchase-report rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks the required purchase permission or the 606 report feature flag is disabled. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The purchase report 606 query failed unexpectedly. | { "message": "Could not load purchase report 606" } |
Returns the regional sale report 607 rows using the same final-sell eligibility rules as the integration sell list when the feature is enabled.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/sale-report-607 |
| Permission | At least one of sell.view, sell.create, direct_sell.access, or view_own_sell_only. |
| Feature flag | config('constants.show_report_607') must be enabled. |
| Eligibility rules | The base query reuses the same final-sell visibility and payment-status restrictions as the integration sell list, including own-sell and commission-agent limits when direct_sell.view is absent. |
is_direct_sale behavior | The filter is only applied when the query parameter is present. 0 means non-direct sells with sub_type = null; 1 means direct sells only. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. The query uses start-of-day/end-of-day datetime bounds. |
location_id, contact_id, created_by | integer | No | Optional location, customer contact, and creator filters. |
payment_status | string | No | paid, due, partial, or overdue. |
is_direct_sale | string | No | 0 or 1. Ignored unless the parameter is present. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
q | string | No | Matches invoice number, customer fields, or numeric transaction/contact ids. |
SaleReport607Row object| Field | Type | Description |
|---|---|---|
transaction_id, invoice_no, sale_date | mixed | Sell identity fields. |
contact_id, customer_display | string | null | Customer reference number and display label. |
total_before_tax, discount_amount, tax_amount, final_total | number | Main sell totals. |
payment_methods | string | null | Resolved payment method label. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.location_id, data.contact_id, data.payment_status, data.created_by, data.is_direct_sale, data.q | mixed | Echoes the applied filters. |
data.items | array<SaleReport607Row> | The current page of regional sell-report rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The report rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks the required sell permission or the 607 report feature flag is disabled. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The sale report 607 query failed unexpectedly. | { "message": "Could not load sale report 607" } |
Returns business activity-log rows using the same filters and structured note payloads as the web Activity Log report.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/reports/activity-log |
| Permission | The token user must be a business admin. |
| Text filters | Supports q or legacy search. The resolved value is returned as data.search and meta.q. |
| Structured fields | note is a structured payload equivalent to the web note column without HTML. changes comes directly from the activity properties. |
| CSV behavior | Exports all matching rows and JSON-encodes note and changes into CSV cells. |
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date, end_date | string | Conditional | Business-format dates. Both must be sent together and start_date must not be after end_date. |
user_id | integer | No | Optional causer filter. |
subject_type | string | No | One of contact, user, sell, purchase, sales_order, purchase_order, sell_return, purchase_return, sell_transfer, stock_adjustment, or expense. |
q, search | string | No | Matches activity description, causer display name, or numeric activity/subject ids. |
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
ActivityLogRow object| Field | Type | Description |
|---|---|---|
id, created_at | mixed | Activity identity and timestamp. |
subject_type, subject_type_label, subject_id | mixed | Raw subject class, translated subject label, and subject id. |
description, description_key | mixed | Translated description text and its raw language key. |
causer_id, causer_display | mixed | Causer identity fields. |
note | object | null | Structured note payload, including refs, status transitions, transaction changes, or other context when present. |
changes | array | object | null | Raw activity changes payload from the logger. |
| Field | Type | Description |
|---|---|---|
data.start_date, data.end_date, data.user_id, data.subject_type, data.search | mixed | Echoes the applied filters and resolved search term. |
data.items | array<ActivityLogRow> | The current page of activity-log rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata and the resolved search term. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The activity-log rows were returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user is not a business admin. | { "message": "Unauthorized" } |
422 | The date pair is incomplete or reversed, a filter failed validation, or q is too short. | Laravel validation JSON or { "message": string }. |
500 | The activity-log query failed unexpectedly. | { "message": "Could not load activity log" } |