Skip to main content

Custom Reports

Reports the business builds itself under Reports > My reports: blocks of numbers, charts and tables, each made from fields you group by and fields you add up. The API lists, creates, changes, deletes and runs them. A report reads the same figures here as in EquipDash, in the export and in the scheduled email.

Plan

Custom reports are on the Pro plan. Other plans get 403 with the code plan_feature_required.

Endpoints​

MethodEndpointDescriptionScope
GET/v1/reports/customList saved reportsreports:read
GET/v1/reports/custom/fieldsFields, block types, date presets and grains a report can usereports:read
GET/v1/reports/custom/{id}One report with its definitionreports:read
GET/v1/reports/custom/{id}/runRun a report and get its figuresreports:read
POST/v1/reports/customCreate a reportreports:write
PATCH/v1/reports/custom/{id}Change its name, definition or email schedulereports:write
DELETE/v1/reports/custom/{id}Delete a reportreports:write

The definition​

{
"dates": { "preset": "last_30_days" },
"date_basis": "booked_on",
"location_id": null,
"blocks": [
{ "type": "numbers", "measures": ["sales", "bookings", "average_booking"] },
{
"type": "chart",
"title": "Sales by month",
"group": [{ "field": "booked_on", "grain": "month" }],
"measures": ["sales"]
},
{
"type": "table",
"title": "Who still owes money",
"group": ["customer"],
"measures": ["bookings", "still_owed"],
"filters": [{ "field": "still_owed", "op": "at_least", "value": 0.01 }],
"sort": { "field": "still_owed", "dir": "desc" }
},
{ "type": "note", "text": "Figures exclude cancelled bookings." }
]
}
KeyDescription
dates.presettoday, yesterday, last_7_days, last_30_days, this_month, last_month, this_year, last_year, all_time or custom. custom needs from and to as YYYY-MM-DD. Dates are in the business's timezone.
date_basisbooked_on (default): the day the booking was made, the same as Sales on the Reports page. booking_date: the day the booking is for.
location_idOne pickup location, or null for all.
blocks[].typenumbers (totals), chart (one figure across one field), table (lines) or note (text). Up to 12 blocks.
blocks[].groupWhat each line or bar is. A field key, or { "field", "grain" } for a date field. Tables take up to 2, charts 1, numbers none. Grains: day, week, month, year, weekday. session_time takes no grain: each start time is its own line, labelled like 12:30 PM in the shop's time zone.
blocks[].measuresWhat to add up. Up to 6.
blocks[].filtersWhat to keep. op is is / is_not (value: a list), contains (text), at_least / at_most (a number) or older_than_days / within_days (for a date figure such as last_booking).

Call GET /v1/reports/custom/fields for the fields this business can use. Rental fields only appear when Rentals is on, experience fields when Experiences is on.

Each block reads the narrowest data that has all its fields: whole bookings, rental items, experiences, payments or the customer list. A block that reads lines says so in source (for example "Rental items only"). Test bookings, drafts, quotes and cancelled bookings are left out, unless a status filter picks cancelled ones. Still owed is worked out per booking, exactly as on the booking page.

Run a report​

GET /v1/reports/custom/{id}/run
{
"data": {
"id": 4,
"name": "Who still owes money",
"dates_label": "All time",
"from": null,
"to": null,
"blocks": [
{
"id": "b1",
"type": "table",
"title": "Who still owes money",
"columns": [
{ "key": "d0", "label": "Customer", "type": "group" },
{ "key": "m0", "label": "Bookings", "type": "count" },
{ "key": "m1", "label": "Still owed", "type": "owed" }
],
"rows": [
[ { "raw": "Jane Doe", "text": "Jane Doe" }, { "raw": 2, "text": "2" }, { "raw": 417.48, "text": "$417.48" } ]
],
"totals": [null, "$417.48"],
"source": null,
"hidden": [],
"error": null,
"truncated": false
}
]
}
}

raw is the number or value; text is formatted in the business's currency and date format. totals line up with the last columns; null where a column cannot be added up. A table shows up to 500 lines and a chart 60 (truncated says when there were more).

Create a report​

POST /v1/reports/custom
{ "name": "Sales by source", "definition": { "dates": { "preset": "this_month" }, "blocks": [ { "type": "table", "group": ["booking_source"], "measures": ["sales"] } ] } }

Returns 201 with the report and its definition. A definition the report cannot use returns 422 with one sentence saying why, for example There is no field called "drop table".

Email a report on a schedule​

PATCH /v1/reports/custom/{id}
{ "schedule": { "every": "weekly", "user_ids": [12, 31] } }

every is daily, weekly (Mondays) or monthly (the 1st). It goes out at 7am in the business's timezone, to team members only, with the whole report attached as a PDF. Send "schedule": null to stop it.