Skip to content

Reports ​

The Reports API provides access to RORCex's library of pre-built analytical reports. Reports can execute synchronously (returning results inline) or asynchronously (returning a run ID for polling). See the async polling guide for the recommended polling pattern.

Reports run against RORCex's synced aggregate store — not a live lane read — so results reflect data as of the last sync from the RORC back office (typically within ~5 minutes), and they remain available even when a lane is offline. See Data Sources & Freshness.


List Reports ​

Return the full catalogue of available reports, including each report's parameter schema and execution metadata.

GET /v1/reports

Authentication: OAuth Token (service_account or user) Permission: rorcex:reports.execute

Response ​

json
{
  "reports": [
    {
      "id": "operational.yesterday_close_summary",
      "pack": "operational",
      "name": "Yesterday Close Summary",
      "description": "End-of-day close totals and exceptions for all stores, for yesterday's business day.",
      "parameter_schema": {
        "type": "object",
        "properties": {
          "stores": { "type": "array", "items": { "type": "string" } }
        },
        "required": []
      },
      "execution_mode": "sync",
      "cache_ttl_seconds": 300,
      "freshness_note": "Data reflects the completed close; re-runs within the TTL window return the cached result."
    }
  ]
}

Status: 200 OK

Response Fields ​

FieldTypeDescription
idstringReport slug — use this as the report_id path parameter in run endpoints
packstringLogical grouping: operational, sales, product, or ops
namestringHuman-readable report name
descriptionstringOne-sentence description of what the report produces
parameter_schemaobjectJSON Schema describing accepted parameters for POST /v1/reports/{report_id}/run
execution_modestringsync (result inline) or async (returns a run ID)
cache_ttl_secondsintegerHow long a completed result is cached before the next run re-executes
freshness_notestringHuman-readable note about data currency and cache behaviour

Registered Reports ​

PackReport IDName
operationaloperational.yesterday_close_summaryYesterday Close Summary
operationaloperational.sales_pace_todaySales Pace Today
operationaloperational.drift_watchlistDrift Watchlist
salessales.department_performance_by_storeDepartment Performance by Store
salessales.gross_margin_by_storeGross Margin by Store
salessales.markdown_summaryMarkdown Summary
salessales.cashier_scorecard_cross_storeCashier Scorecard Cross-Store
salessales.hourly_pace_heatmapHourly Pace Heatmap
salessales.department_traffic_scatterDepartment Analysis: Weekly Sales vs. Foot Traffic
productproduct.retail_variance_cross_storeRetail Variance Cross-Store
productproduct.price_change_historyPrice Change History
productproduct.slow_movers_cross_storeSlow Movers Cross-Store
productproduct.catalog_gap_detectionCatalog Gap Detection
opsops.refund_void_auditRefund & Void Audit
opsops.inventory_adjustment_auditInventory Adjustment Audit
opsops.outlier_store_flaggingOutlier Store Flagging

The authoritative list of accepted parameters for each report is its parameter_schema field. Consult the list endpoint for the current schema before constructing a run request.

Errors ​

See /reference/errors.


Run Report ​

Execute a report. Supply parameters that satisfy the report's parameter_schema. Synchronous reports return results directly; asynchronous reports return a run ID for polling.

POST /v1/reports/{report_id}/run

Authentication: OAuth Token (service_account or user) Permission: rorcex:reports.execute

Path Parameters ​

ParameterTypeRequiredDescription
report_idstringYesReport slug (e.g., sales.department_performance_by_store)

Request Body ​

The request body is a JSON object whose fields are validated against the target report's parameter_schema. Retrieve the schema from GET /v1/reports before submitting.

json
{
  "stores": ["org_00000k1L2m3N4o5", "org_00000a1B2c3D4e5"],
  "from": "2026-06-01",
  "to": "2026-06-11"
}

Response — Synchronous (execution_mode: "sync") ​

json
{
  "result": {
    "data": [
      { "store_org_id": "org_00000k1L2m3N4o5", "DeptCode": "01", "NetSales": 41820.75 }
    ],
    "source": "cache",
    "generated_at": "2026-06-11T08:00:00Z",
    "params_echo": {
      "stores": ["org_00000k1L2m3N4o5", "org_00000a1B2c3D4e5"],
      "from": "2026-06-01",
      "to": "2026-06-11"
    },
    "freshness_label": "Cached result from 08:00 UTC",
    "warnings": [],
    "cache_hit": true
  }
}

Status: 200 OK

Response Fields — Synchronous ​

FieldTypeDescription
result.dataarrayReport rows, in each report's own schema. HQ-aggregate-backed reports return snake_case rows.
result.sourcestringlive (freshly executed) or cache (served from cache)
result.generated_atstring (ISO 8601)When this result was generated
result.params_echoobjectThe parameters that produced this result
result.freshness_labelstringHuman-readable freshness description
result.warningsarrayNon-fatal warnings (e.g., one store returned no data)
result.cache_hitbooleantrue if served from the result cache, false if freshly executed.

Response — Asynchronous (execution_mode: "async") ​

json
{
  "run_id": "01J9XS5M8Q9WP3ZR7AC4VHE1XD",
  "status": "pending",
  "poll_url": "/api/v1/reports/runs/01J9XS5M8Q9WP3ZR7AC4VHE1XD",
  "estimated_seconds": 12
}

Status: 202 Accepted

Response Fields — Asynchronous ​

FieldTypeDescription
run_idstringPublic run ID — use with GET /v1/reports/runs/{public_id}
statusstringInitial status: always "pending"
poll_urlstringConvenience URL for polling the run status
estimated_secondsintegerEstimated time to completion in seconds

See the async polling guide for the recommended polling pattern.

Errors ​

StatusErrorDescription
404report_not_foundNo report matches the given report_id
422report_param_validation_failedBody does not satisfy the report's parameter_schema
422report_failedReport executed but produced no result

See /reference/errors for error envelope shapes.


Get Run Status ​

Poll the status of an asynchronous report run.

GET /v1/reports/runs/{public_id}

Authentication: OAuth Token (service_account or user) Permission: rorcex:reports.execute

Path Parameters ​

ParameterTypeRequiredDescription
public_idstringYesThe run ID returned by POST /v1/reports/{report_id}/run

Response ​

json
{
  "run_id": "01J9XS5M8Q9WP3ZR7AC4VHE1XD",
  "report_id": "sales.department_performance_by_store",
  "status": "completed",
  "params_echo": {
    "stores": ["org_00000k1L2m3N4o5"],
    "from": "2026-06-01",
    "to": "2026-06-11"
  },
  "created_at": "2026-06-11T09:00:00Z",
  "started_at": "2026-06-11T09:00:01Z",
  "completed_at": "2026-06-11T09:00:13Z",
  "result": { "data": [], "source": "live", "generated_at": "2026-06-11T09:00:13Z", "params_echo": {}, "freshness_label": "Live result", "warnings": [] },
  "error_class": null,
  "error_message": null
}

Status: 200 OK

Response Fields ​

FieldTypeDescription
run_idstringPublic run ID
report_idstringReport slug that was executed
statusstringOne of: pending, running, completed, errored
params_echoobjectParameters submitted with the run
created_atstring (ISO 8601)When the run was enqueued
started_atstring or null (ISO 8601)When execution began; null if still pending
completed_atstring or null (ISO 8601)When execution finished; null if not yet complete
resultobject or nullPopulated when status is completed — same shape as the synchronous result
error_classstring or nullError class name when status is errored
error_messagestring or nullHuman-readable error description when status is errored

A run is visible only to callers acting in the organization that requested it (X-Organization-Context). Within that organization, the user or service account that queued it can always read it; anyone else must also send the same store scope the run was computed under (the same set of stores, resolved from X-Organization-Context / X-Organization-Scope). Otherwise this endpoint, Get Run Result and Export Run Result return 403 — run the report yourself instead.

Errors ​

See /reference/errors.


Get Run Result ​

Retrieve the completed result for a run directly, without the run metadata envelope.

GET /v1/reports/runs/{public_id}/result

Authentication: OAuth Token (service_account or user) Permission: rorcex:reports.execute

Path Parameters ​

ParameterTypeRequiredDescription
public_idstringYesThe run ID

Response ​

json
{
  "result": {
    "data": [
      { "store_org_id": "org_00000k1L2m3N4o5", "DeptCode": "01", "NetSales": 41820.75 }
    ],
    "source": "live",
    "generated_at": "2026-06-11T09:00:13Z",
    "params_echo": {},
    "freshness_label": "Live result",
    "warnings": []
  }
}

Status: 200 OK

Returns 404 when the run does not exist or is not yet complete, and 403 when it belongs to a different organization or a different store scope (see Get Run Status).

Errors ​

See /reference/errors.


Export Report ​

Run a report and download its rows as a CSV file instead of JSON. Parameters, store scoping and result caching are exactly those of Run Report — an export can never return rows the same caller could not get from run.

POST /v1/reports/{report_id}/export?format=csv

Authentication: OAuth Token (service_account or user) Permission: rorcex:reports.execute + rorcex:reports.view + rorcex:reports.export

Path Parameters ​

ParameterTypeRequiredDescription
report_idstringYesReport slug (e.g., operational.yesterday_close_summary)

Query Parameters ​

ParameterTypeRequiredDescription
formatstringNocsv (the default and only supported format)
bombooleanNo1 (default) starts the file with a UTF-8 byte-order mark so Excel decodes accented text. Pass 0 when a script reads the file as plain UTF-8, or the mark becomes part of the first column name

Request Body ​

The report parameters, exactly as for POST /v1/reports/{report_id}/run. format travels in the query string so it never collides with a report parameter.

json
{
  "date": "2026-06-10"
}

Response — CSV ​

HTTP/1.1 200 OK
Content-Type: text/csv; charset=UTF-8
Content-Disposition: attachment; filename="operational-yesterday-close-summary-20260611-080000.csv"

Store Org ID,Store Name,Timezone,Business Day Date,Status,Beginning Balance,Total Sales Amount,...
org_00000k1L2m3N4o5,Main Street,America/New_York,2026-06-10,C,100,41820.75,...

The file is UTF-8 with CRLF line endings, and starts with a byte-order mark unless you pass bom=0. The filename is the report id plus the result's UTC generated_at.

How rows become columns:

Value in a result rowIn the CSV
ScalarOne column. Booleans export as true / false; null as an empty cell
Nested objectOne column per field, headed Parent - Field
List of scalars (e.g. missing_from_stores)One column, values joined with ;
List of objects (e.g. retail variance's stores)One CSV line per element, the row's other columns repeated on each. If a row holds more than one such list, they are JSON-encoded instead

Headers are the row keys in human-readable form (store_org_id → Store Org ID, variance_pct → Variance %). Every store_org_id column is followed by a Store Name column holding the store's name as the Reports page shows it (empty when the store has none, or is not one you can see). Columns are the union of every row's keys, in first-seen order. Text cells that a spreadsheet would read as a formula (starting =, +, -, @) are prefixed with '; numbers are not.

Result metadata (warnings, fidelity, freshness_label) is not part of the file — read it from run when you need it. One exception: when the report assessed store coverage, the response carries an X-Report-Coverage header (full, partial or none). none means no store in scope could report, so an empty file means "could not check", not "nothing found".

Response — Report Queued (202 Accepted) ​

A report that runs asynchronously for the given parameters cannot be exported in the same request. The response is the async run envelope from Run Report plus an export_url; download that once the run is completed.

json
{
  "run_id": "01J9XS5M8Q9WP3ZR7AC4VHE1XD",
  "status": "pending",
  "poll_url": "/api/v1/reports/runs/01J9XS5M8Q9WP3ZR7AC4VHE1XD",
  "estimated_seconds": 30,
  "export_url": "/api/v1/reports/runs/01J9XS5M8Q9WP3ZR7AC4VHE1XD/export?format=csv"
}

export_url carries bom=0 when you passed it.

Errors ​

StatusErrorDescription
403—Caller lacks one of the three permissions
404report_not_foundNo report matches the given report_id
422(validation)format or bom has an unsupported value
422report_param_validation_failedBody does not satisfy the report's parameter_schema
422report_failedReport could not run (e.g. none of the requested store_org_ids are in scope)

Export Run Result ​

Download a completed asynchronous run's result as a CSV file. Rows, the Store Name column and the X-Report-Coverage header are exactly as for Export Report.

GET /v1/reports/runs/{public_id}/export?format=csv

Authentication: OAuth Token (service_account or user) Permission: rorcex:reports.execute + rorcex:reports.view + rorcex:reports.export

Path Parameters ​

ParameterTypeRequiredDescription
public_idstringYesThe run ID

Query Parameters ​

ParameterTypeRequiredDescription
formatstringNocsv (the default and only supported format)
bombooleanNo1 (default) starts the file with a UTF-8 byte-order mark so Excel decodes accented text. Pass 0 when a script reads the file as plain UTF-8, or the mark becomes part of the first column name

Status: 200 OK with a text/csv attachment.

The user or service account that queued the run can always export it. Anyone else in the same organization must also send the store scope the run was computed under (the same set of stores, resolved from X-Organization-Context / X-Organization-Scope), so a colleague with fewer stores cannot download a wider run's rows — run the report yourself instead.

Errors ​

StatusDescription
403Caller lacks one of the three permissions, the run belongs to a different organization, or another caller queued it over a different store scope (run the report yourself)
404The run does not exist or is not yet completed
422format or bom has an unsupported value

ShopHero CommerceCore Platform