Skip to content
SarvexDocs
Esc
↑↓navigate↵open⌘Jpreview

Daily time series of funnel/revenue counts

Max range 92 days. Never a raw scan — served entirely from the precomputed daily aggregate.

GET/channel/daily
Authorization
AuthorizationBearer token (JWT) · headerrequired

JWT issued by the external IdP via the OAuth 2.0 authorization-code flow (Kinde in production; a simulator in test). The client obtains it and sends it as a Bearer token on every authenticated call. Sarvex's services verify it — issuer, audience, signature (IdP JWKS), expiry — and read identity and tenant from its claims. Sarvex does not issue or revoke these tokens. merchant_id/store_id are read from the verified claims (and the merchant→store mapping), never from the URL. The operator scope is required for /operator/*. Operators acting on a specific merchant pass the X-Operate-As header, which is recorded in the audit log.

Query parameters
fromstring<date>

yyyy-MM-dd, inclusive. Defaults to 29 days before to. Range with to is capped at 92 days.

tostring<date>

yyyy-MM-dd, inclusive. Defaults to today (UTC). Range with from is capped at 92 days.

surfacechannel_surface

Restrict to one surface. Omit for the all-surfaces combined rollup.

Allowed:google_ai_modegoogle_geminiopenai_chatgptother_agentunknown
store_idstring
Responses
200

One row per store/surface/day in range.

datachannel_daily_entry[]required
Show properties
Array of channel_daily_entry
datestring<date>
surfacechannel_surface

Closed multi-surface enum. openai_chatgpt is defined but never populated today — no signal in this codebase distinguishes ChatGPT/ACP traffic from any other non-Google agent yet; it exists so a future surface requires no schema migration. Only ever appears on a single store/surface/day row (channel_daily_entry); never "all" — see channel_surface_or_all for the combined-row field.

Allowed:google_ai_modegoogle_geminiopenai_chatgptother_agentunknown
store_idstring
sessionsinteger
sessions_confirmedinteger

sessions minus sessions_inferred.

sessions_inferredinteger
sessions_reached_cartinteger
sessions_reached_checkoutinteger
checkouts_initiatedinteger
checkouts_completedinteger
revenue_minorinteger
currencystring | null

This row's own currency — a single store/surface/day is never ambiguous the way a summed range can be, so no currency_mixed flag exists here.

discovery_requestsinteger

Request-level count of pre-checkout catalog-search/lookup traffic — never sessionized (no correlation identifier exists for it); never presented as a session count.

rateschannel_rates

Derived at read time from stored counts (R7) — never itself stored.

Show properties
cart_ratenumber<double>

sessions_reached_cart / sessions.

checkout_ratenumber<double>

sessions_reached_checkout / sessions_reached_cart.

completion_ratenumber<double>

checkouts_completed / checkouts_initiated.

aov_minorinteger

revenue_minor / checkouts_completed, zero-safe.

pagepagerequired
Show properties
cursorstring | nullrequired
has_morebooleanrequired
403

Authenticated but not permitted (e.g. non-operator on an operator route).

errorobjectrequired
Show properties
codestringrequired
messagestringrequired
detailsobject | null
422

Request body failed validation.

errorobjectrequired
Show properties
codestringrequired
messagestringrequired
detailsobject | null
Try it
Server
Authorization
Parameters
Request
curl -X GET "https://api.sarvex.example.com/v1/channel/daily" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "data": [
    {
      "date": "2019-08-24",
      "surface": "google_ai_mode",
      "store_id": "string",
      "sessions": 0,
      "sessions_confirmed": 0,
      "sessions_inferred": 0,
      "sessions_reached_cart": 0,
      "sessions_reached_checkout": 0,
      "checkouts_initiated": 0,
      "checkouts_completed": 0,
      "revenue_minor": 0,
      "currency": "string",
      "discovery_requests": 0,
      "rates": {
        "cart_rate": 0.1,
        "checkout_rate": 0.1,
        "completion_rate": 0.1,
        "aov_minor": 0
      }
    }
  ],
  "page": {
    "cursor": "string",
    "has_more": true
  }
}