Set up a schedule to produce a board-prep review of each monthly, quarterly or annual period from your NetSuite data, and deliver it to the people you choose.
What the review contains
Each review covers your period, the prior period of the same length, and the same period a year earlier.
| Section | Included |
|---|---|
| Review summary with KPIs and flags | Always |
| Comparative income statement | Always |
| Revenue trend and journal split | Always |
| A/R aging and top balances | Always |
| Balance sheet snapshot and cash movement | Always |
| Customer concentration | Optional |
| Customer activity and invoice review | Optional |
| Revenue by subsidiary | Optional |
| A/P aging and top vendors | Optional |
| Open sales order backlog | Optional |
The always-included sections must succeed for the review to publish. An optional section that NetSuite can’t return is listed as unavailable.
How flags work
The summary raises flags from fixed rules, each with the question it’s likely to prompt. Check anything under Resolve before presenting before you share the review. Examples:
| Flag | When it’s raised |
|---|---|
| Journal entries drive reported revenue | Journals are at least 25% of revenue. At 50% it must be resolved before presenting. |
| Large share of receivables over 90 days past due | At least 30% of open receivables. At 50% it must be resolved before presenting. |
| Invoices with a TEST memo in production | A large invoice has a memo starting with “TEST”. Must be resolved before presenting. |
| Revenue concentrated in top customers | The top ten customers are at least 60% of revenue. |
| Gross margin moved more than 10 points year over year | Margin moved by 10 points or more. |
| Review period is still open | A period isn’t closed, so figures may change. |
The flags highlight questions in your data. They aren’t an audit or an opinion on the figures.
Create a schedule
Connect NetSuite first, then create the schedule:
curl -X POST "$SURESHAKE_API/v2/reporter/report-schedules" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entityId": "<company id>",
"reportingIntentId": "periodic_performance_review",
"name": "Quarterly board pack",
"cadence": "quarterly",
"runDayOffset": 5,
"timezone": "America/New_York",
"distribution": {
"viewerGroupIds": ["<viewer group id>"],
"emails": ["board@example.com"],
"permission": "read"
}
}'cadenceismonthly,quarterlyorannual.runDayOffsetis how many days after the period ends to run, from 0 to 60. The default is 5, to give your books time to close.timezonesets when it fires: 06:00 local time on that day. The default is UTC.firstPeriodStartis optional. By default, the first period is the most recent complete one.distributionnames up to 50 viewer groups and 50 email addresses.
What happens each period
- The schedule runs for its period, pulling the data and building the review.
- The review is published as a report.
- Viewer groups get access, and each email address gets an invitation. See Share reports for what recipients see.
- Each delivery is recorded individually, so a partial send is visible.
Manage a schedule
All of these are under /v2/reporter/report-schedules:
| To do this | Call |
|---|---|
| See schedules | GET with entityId |
| Run the next period now | POST /{id}/run-now |
| Check each run, its report and its deliveries | GET /{id}/occurrences |
| Change cadence, timing or recipients | PATCH /{id} |
| Turn it off and keep its history | DELETE /{id} |
Run a single review
To run one review without a schedule, create a Reporter run with the intent periodic_performance_review and the source netsuite, then call POST /v2/reporter-execution-runs/{id}/provider-acquisition/netsuite/periodic-review. You can set:
periodStartandperiodEndasOfDatefor aging and the balance sheet snapshotsubsidiaryIdfor one subsidiarytrendMonthsfrom 3 to 36 (default 12)selectedOptionalSections
See the API reference.
Before you rely on a schedule
- A schedule runs as the person who created it. It needs a working NetSuite connection for the company.
- If a run fails, it shows as failed in
occurrenceswith its error. Check after the first few runs.