Pular para o conteúdo

Reports

Este conteúdo não está disponível em sua língua ainda.

The Reports resource provides read-only analytics aggregations over your tenant’s data, fourteen report types in all. Every endpoint requires the reports.read scope.

There are two shapes of report endpoint:

  • The two originals: /reports/summary and /reports/revenue/daily, take start/end (YYYY-MM-DD) and return their own dedicated response shapes.
  • The twelve passthrough reports (sales-summary, transaction-log, tax, margins, ar-aging, eod, store-credit, discounts, inventory-valuation, sales-by-customer, sales-by-item, turnaround) return the uniform report envelope. Windowed reports take from/to; eod takes a single day; as-of snapshot reports reject date windows. Check the report catalog for each endpoint. These are the same reports the in-app Reports tab renders, with data supplied by the app’s report engine.

Money fields follow the money object convention (amount_cents, amount, currency).


GET /api/v1/reports

Returns an index of the available report endpoints with their required and optional parameters.

Scope required: reports.read

Terminal window
curl https://app.benchkey.com/api/v1/reports \
-H "Authorization: Bearer bk_live_<tenantId>_<secret>"
const res = await fetch("https://app.benchkey.com/api/v1/reports", {
headers: { Authorization: "Bearer bk_live_<tenantId>_<secret>" },
});
const index = await res.json();
{
"object": "list",
"data": [
{
"report_type": "summary",
"path": "/api/v1/reports/summary",
"description": "Revenue, ticket volume, estimates, and device breakdown for a date window.",
"required_params": ["start", "end"],
"optional_params": ["location_id"]
},
{
"report_type": "revenue_daily",
"path": "/api/v1/reports/revenue/daily",
"description": "Day-by-day revenue series for a date window.",
"required_params": ["start", "end"],
"optional_params": ["location_id"]
},
{
"report_type": "sales-summary",
"path": "/api/v1/reports/sales-summary",
"description": "Net revenue, COGS, refunds, gross profit, and margin for a date window.",
"required_params": ["from", "to"],
"optional_params": ["location_id"]
}
]
}

The live index lists all fourteen report types with their exact required and optional parameters, use it for discovery rather than hardcoding.


The twelve passthrough reports all return the same stable wrapper:

{
"object": "report",
"report": "sales-summary",
"window": { "from": "2026-06-01", "to": "2026-06-30" },
"data": { "...": "the report's own JSON shape, unchanged from the in-app report engine" }
}
FieldTypeDescription
objectstringAlways "report"
reportstringReport name, e.g. "sales-summary"
windowobjectThe normalized date window, { "from": null, "to": null } for as-of snapshot reports
dataobjectThe report payload. The shape varies per report and is single-sourced from the in-app report engine
ReportPathWhat it returnsWindowlocation_id
sales-summaryGET /api/v1/reports/sales-summaryNet revenue, COGS, refunds, gross profit, and margin for a date windowfrom + toyes
transaction-logGET /api/v1/reports/transaction-logEvery payment, refund, and cash-drawer adjustment in a date windowfrom + toyes
taxGET /api/v1/reports/taxTax collected by jurisdiction for a date window (cash basis)from + toyes
marginsGET /api/v1/reports/marginsProfitability / cost-of-goods analysis for a date windowfrom + toyes
ar-agingGET /api/v1/reports/ar-agingOutstanding receivables bucketed by ageas-of snapshotyes
eodGET /api/v1/reports/eodEnd-of-day (Z) report for a single day: payments by method, register sessions, cash drawerfrom (single day)yes
store-creditGET /api/v1/reports/store-creditOutstanding store-credit liability by customeras-of snapshotno
discountsGET /api/v1/reports/discountsDiscounts given in a date window, by tech and by dayfrom + tono
inventory-valuationGET /api/v1/reports/inventory-valuationOn-hand inventory quantity and valueas-of snapshotyes
sales-by-customerGET /api/v1/reports/sales-by-customerTop customers by paid revenue for a date windowfrom + tono
sales-by-itemGET /api/v1/reports/sales-by-itemTop line items by paid revenue for a date windowfrom + tono
turnaroundGET /api/v1/reports/turnaroundTicket turnaround times: distribution, WIP aging, and medians for a date windowfrom + tono
ParameterTypeDescription
fromstringWindow start, ISO date (YYYY-MM-DD) or epoch milliseconds. Required for windowed reports; for eod it names the single day
tostringWindow end (inclusive), ISO date (YYYY-MM-DD) or epoch milliseconds. Required for windowed reports; for eod it is optional and must resolve to the same day as from
location_idintegerFilter to a single location, only on reports marked “yes” above

Parameter rules are strict rather than silently ignored: as-of snapshot reports reject from/to (400 invalid_query), and passing location_id to a report that doesn’t support it is also a 400 invalid_query, no placebo filters.

Terminal window
curl "https://app.benchkey.com/api/v1/reports/sales-summary?from=2026-06-01&to=2026-06-30" \
-H "Authorization: Bearer bk_live_<tenantId>_<secret>"
const params = new URLSearchParams({ from: "2026-06-01", to: "2026-06-30" });
const res = await fetch(
`https://app.benchkey.com/api/v1/reports/sales-summary?${params}`,
{ headers: { Authorization: "Bearer bk_live_<tenantId>_<secret>" } }
);
const { report, window, data } = await res.json();
HTTPCodeDescription
400invalid_queryMissing/malformed from/to, from after to, a window supplied to an as-of snapshot report, eod given two different days, or location_id on a report that doesn’t support it
400invalid_paramlocation_id is not a positive integer
402payment_requiredThe tenant’s plan does not include advanced reports
404not_foundlocation_id does not match any location

GET /api/v1/reports/summary

Returns aggregated revenue, ticket volume, estimate conversion, and device breakdown for a date window. Use this for dashboard-style metrics.

Scope required: reports.read

ParameterTypeRequiredDescription
startstring (date)YesWindow start date, YYYY-MM-DD
endstring (date)YesWindow end date, YYYY-MM-DD (inclusive)
location_idstringNoFilter to a single location (must be a positive integer); returns 404 if the location does not exist
Terminal window
curl "https://app.benchkey.com/api/v1/reports/summary?start=2025-01-01&end=2025-01-31" \
-H "Authorization: Bearer bk_live_<tenantId>_<secret>"
const params = new URLSearchParams({ start: "2025-01-01", end: "2025-01-31" });
const res = await fetch(
`https://app.benchkey.com/api/v1/reports/summary?${params}`,
{ headers: { Authorization: "Bearer bk_live_<tenantId>_<secret>" } }
);
const report = await res.json();
{
"object": "report",
"report_type": "summary",
"period": {
"start": "2025-01-01",
"end": "2025-01-31",
"location_id": null
},
"revenue": {
"total": { "amount_cents": 1250000, "amount": "12500.00", "currency": "USD" },
"tax_collected": { "amount_cents": 112500, "amount": "1125.00", "currency": "USD" },
"total_refunded": { "amount_cents": 5000, "amount": "50.00", "currency": "USD" },
"paid_invoice_count": 143,
"avg_invoice": { "amount_cents": 8741, "amount": "87.41", "currency": "USD" }
},
"tickets": {
"total_created": 211,
"total_completed": 198,
"current_backlog": 37,
"avg_turnaround_hours": 14.2
},
"estimates": {
"total_sent": 58,
"approved": 41,
"declined": 9,
"pending": 8,
"conversion_rate": "70.7",
"avg_value": { "amount_cents": 9500, "amount": "95.00", "currency": "USD" },
"approved_revenue": { "amount_cents": 389500, "amount": "3895.00", "currency": "USD" }
},
"devices": [
{ "device": "iPhone 14 Pro", "count": 52 },
{ "device": "Samsung Galaxy S23", "count": 34 },
{ "device": "iPad Air", "count": 18 }
]
}
FieldTypeDescription
startstringWindow start date
endstringWindow end date (inclusive)
location_idstring|nullLocation filter applied, or null
FieldTypeDescription
totalmoneyGross revenue from paid and refunded invoices
tax_collectedmoneySum of tax on paid/refunded invoices
total_refundedmoneySum of refunded amounts
paid_invoice_countintegerNumber of paid or refunded invoices
avg_invoicemoneyAverage invoice value (total / paid_invoice_count); $0.00 when count is 0

All ticket-linked aggregates apply the same visibility contract as GET /api/v1/tickets: hidden, soft-deleted, and billing-only tickets are excluded from every field below.

FieldTypeDescription
total_createdintegerTickets created in the date window (excludes hidden, soft-deleted, and billing-only tickets)
total_completedintegerCompletion events in the window (not undone); excludes completions linked to hidden/soft-deleted/billing-only tickets
current_backlogintegerActive (not-removed) queue entries right now; excludes entries linked to hidden/soft-deleted/billing-only tickets
avg_turnaround_hoursnumber|nullAverage hours from queue entry added to removed, for tickets completed in the window; excludes hidden/soft-deleted/billing-only tickets; null if no data

Estimate counts also apply the ticket visibility contract, estimates linked to hidden, soft-deleted, or billing-only tickets are excluded.

FieldTypeDescription
total_sentintegerEstimates created in the window (excludes those linked to hidden/soft-deleted/billing-only tickets)
approvedintegerEstimates with an approved_at timestamp
declinedintegerEstimates with a declined_at timestamp
pendingintegertotal_sent − approved − declined
conversion_ratestringApproval rate as a percentage string, e.g. "70.7"
avg_valuemoneyAverage estimate total across all sent
approved_revenuemoneySum of totals for approved estimates

Array of up to 30 entries, sorted by count descending:

FieldTypeDescription
devicestringDevice label from the ticket
countintegerNumber of tickets for this device in the window (excludes billing-only and hidden tickets)
HTTPCodeDescription
400missing_paramsstart or end not provided
400invalid_date_formatEither date is not YYYY-MM-DD
400invalid_filterDate passes format check but is not a real calendar date (e.g. month 13, day 32)
400invalid_date_rangestart is after end
400invalid_paramlocation_id is not a positive integer
400invalid_paramsA parameter was passed as a non-scalar value (e.g. array)
404not_foundlocation_id does not match any location

GET /api/v1/reports/revenue/daily

Returns a day-by-day revenue series for a date window. Read revenue_basis before interpreting the amounts: net_of_refunds uses the settlement projection, while gross identifies the legacy invoice-based calculation. Settlement activity is dated by money events, including refunds on their own dates. A refund-only day can therefore have negative revenue. Days without qualifying activity are omitted.

Scope required: reports.read

ParameterTypeRequiredDescription
startstring (date)YesWindow start date, YYYY-MM-DD
endstring (date)YesWindow end date, YYYY-MM-DD (inclusive)
location_idstringNoFilter to a single location (must be a positive integer); returns 404 if the location does not exist
Terminal window
curl "https://app.benchkey.com/api/v1/reports/revenue/daily?start=2025-01-01&end=2025-01-07" \
-H "Authorization: Bearer bk_live_<tenantId>_<secret>"
const params = new URLSearchParams({ start: "2025-01-01", end: "2025-01-07" });
const res = await fetch(
`https://app.benchkey.com/api/v1/reports/revenue/daily?${params}`,
{ headers: { Authorization: "Bearer bk_live_<tenantId>_<secret>" } }
);
const report = await res.json();
{
"object": "report",
"report_type": "revenue_daily",
"revenue_basis": "net_of_refunds",
"period": {
"start": "2025-01-01",
"end": "2025-01-07",
"location_id": null
},
"data": [
{
"date": "2025-01-01",
"revenue": { "amount_cents": 42500, "amount": "425.00", "currency": "USD" },
"tax_collected": { "amount_cents": 3825, "amount": "38.25", "currency": "USD" },
"invoice_count": 5
},
{
"date": "2025-01-02",
"revenue": { "amount_cents": 91000, "amount": "910.00", "currency": "USD" },
"tax_collected": { "amount_cents": 8190, "amount": "81.90", "currency": "USD" },
"invoice_count": 11
},
{
"date": "2025-01-03",
"revenue": { "amount_cents": -5000, "amount": "-50.00", "currency": "USD" },
"tax_collected": { "amount_cents": -450, "amount": "-4.50", "currency": "USD" },
"invoice_count": 1
}
]
}
FieldTypeDescription
datestringCalendar date (YYYY-MM-DD)
revenuemoneyRevenue for that day on the returned revenue_basis; settlement refunds subtract from it
tax_collectedmoneyTax for that day’s qualifying activity, including refund adjustments on the settlement basis
invoice_countintegerDistinct invoices with qualifying money activity that day on the settlement basis; a deposit without an invoice counts its estimate or ticket target once. The legacy gross basis counts paid or refunded invoices

The top-level revenue_basis is net_of_refunds or gross. On the settlement basis, deposits without an invoice can contribute revenue, and the same invoice can count on both its payment day and a later refund day. Qualifying payments and refunds that cancel each other out can leave a zero-total day in the series. Imported shops may use the same legacy presentation as the app’s Overview within the settlement projection.

Only the gross fallback dates invoice totals by paid_at, falling back to created_at; it does not subtract refunds. The separate analytics summary retains its documented gross revenue semantics.

HTTPCodeDescription
400missing_paramsstart or end not provided
400invalid_date_formatEither date is not YYYY-MM-DD
400invalid_filterDate passes format check but is not a real calendar date (e.g. month 13, day 32)
400invalid_date_rangestart is after end
400invalid_paramlocation_id is not a positive integer
400invalid_paramsA parameter was passed as a non-scalar value (e.g. array)
404not_foundlocation_id does not match any location
Status do sistema