Demand signals
Returns demand signals — planned and actual revenue and traffic values per day, with pagination and filters by period and department.
Scope
Requires the demand.read scope — the only "monetary" scope in v1: the resource includes revenue data. That's why its checkbox in the key-creation UI is off by default and labeled "includes revenue data" — grant it deliberately. Without the scope, the key gets 403 missing_scope. See Scopes and permissions → Scope table for which permission the key's creator needs to grant this scope.
Query parameters
| Parameter | Required | Description |
|---|---|---|
limit |
no | Integer 1..200, defaults to 100. |
cursor |
no | The meta.next_cursor value from the previous response — for the next page. |
from, to |
no | YYYY-MM-DD dates in the organization's timezone, boundaries inclusive — filters by date. Passed only as a pair; the maximum range is 366 days. When omitted, the current calendar month is used. |
department_id |
no | A department UUID — exact match on the signal's own column. An unknown or another organization's department_id is not an error, it just returns an empty list. |
Rows with department_id = null — a signal for the whole location — are returned only when the department_id filter is not passed. A request with any department_id returns strictly that department's rows: location-wide signals don't appear in it. To get both the location-wide and the per-department rows, request without the filter and split them by department_id on your side.
employee_id is not supported on this resource: demand signals aren't tied to employees, so passing it returns 400 validation_error (the parameter is explicitly rejected, not silently ignored — see Conventions → Filters). Passing only from without to (or vice versa) is also rejected — 400 with the hint pass both from and to, or neither.
Request
Without parameters — the current month's signals in the organization's timezone:
curl -s https://smengo.com/api/v1/demand-signals \
-H "Authorization: Bearer smg_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
For a specific period:
curl -s "https://smengo.com/api/v1/demand-signals?from=2026-07-01&to=2026-07-31" \
-H "Authorization: Bearer smg_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Response
{
"data": [
{
"id": "a1c3e5b7-9d2f-4a6c-8e0b-3f5d7a9c1e24",
"department_id": null,
"date": "2026-07-14",
"metric": "revenue",
"kind": "fact",
"value": 48250.75,
"source": "poster",
"updated_at": "2026-07-15T02:10:05.000Z"
},
{
"id": "8e0c2a4f-6b1d-4e9a-b3c5-7d9f1b3e5a70",
"department_id": "9c1a2e34-5678-4abc-9def-0123456789ab",
"date": "2026-07-14",
"metric": "traffic",
"kind": "plan",
"value": 320,
"source": "manual",
"updated_at": "2026-07-10T09:41:18.000Z"
}
],
"meta": { "next_cursor": null }
}
Response fields
| Field | Type | Description |
|---|---|---|
id |
string (uuid) |
The signal's unique identifier. |
department_id |
string (uuid) | null |
The signal's department (see Departments); null — a signal for the whole location (see the filtering rule above). |
date |
string (YYYY-MM-DD) |
The signal's day, in the organization's timezone; the list is sorted by this field (plus id as a tiebreaker). |
metric |
"revenue" | "traffic" |
The metric: revenue or traffic (guest/receipt count). |
kind |
"plan" | "fact" |
Whether this is a plan or an actual. |
value |
number |
The metric's value — a JSON number, not a string: non-negative, at most 10¹². For revenue it can be fractional (48250.75); for traffic it's usually an integer. |
source |
"manual" | "csv" | "poster" |
Where the signal came from: manual entry, CSV import, or the Poster POS integration. |
updated_at |
string (ISO 8601 UTC) |
When the signal was last updated. |
Signals aren't tied to employees — the response contains neither employee_id nor embedded employee data.
Pagination
The list is sorted by date, id. If there are more signals than limit, meta.next_cursor holds a cursor for the next page — pass it verbatim as cursor on the next request:
curl -s "https://smengo.com/api/v1/demand-signals?limit=1&cursor=eyJrIjoiMjAyNi0wNy0xNCIsImlkIjoiYTFjM2U1YjctOWQyZi00YTZjLThlMGItM2Y1ZDdhOWMxZTI0In0" \
-H "Authorization: Bearer smg_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
meta.next_cursor is null once there are no more signals. Full pagination rules are in Conventions → Pagination.
What's next
- Departments — resolving
department_id. - Scopes and permissions — who can grant a key
demand.readand why it's off by default. - Conventions — the shared filter and date rules.