Skip to content

API reference

Read published daily sessions

POST
/v1/query

Returns published daily sessions for one connection and a window of at most 31 days, with full provenance.

The window is not gated on UTC: a “through yesterday” query from a UTC+2 property just after local midnight is answered rather than refused. What gates the answer is publication — every date in the window must have a published head. If some do, the response is 409 data_incomplete and names the missing dates; if none do, 409 data_not_ready.

Authorization is checked before the read and again before the response is released, so a key revoked while ClickHouse is in flight yields 401 and no data. The workspaceId in the body must equal the key’s own workspace; a mismatch is 403, never a cross-tenant read. Workspace headers are ignored.

The query request body. metric and dimensions are fixed in this version. There is no filter, no segment and no free-form SQL: the query surface cannot express anything the published layer cannot answer.

object
workspaceId
required

Must equal the API key’s own workspace.

string
/^[A-Za-z0-9_-]{1,128}$/
connectionId
required
string
/^[A-Za-z0-9_-]{1,128}$/
propertyId
required

GA4 numeric property id, as a string.

string
/^[1-9][0-9]{0,19}$/
startDate
required

Calendar date in the property’s reporting timezone.

string format: date
endDate
required

Inclusive. The closed interval must contain 1–31 days. Publication gates query availability; there is no independent UTC-today check at the query boundary.

string format: date
metric
required
string
Allowed value: ga4.sessions
dimensions
required
Array<string>
>= 1 items <= 1 items
Example
{
"workspaceId": "your_workspace",
"connectionId": "your_connection",
"propertyId": "123456789",
"startDate": "2026-08-31",
"endDate": "2026-09-04",
"metric": "ga4.sessions",
"dimensions": [
"date"
]
}

Every requested day has a complete published snapshot.

object
metric
required
string
Allowed value: ga4.sessions
rows
required

One row per requested date, in ascending date order, with no gaps.

Array<object>
>= 1 items <= 31 items
object
date
required
string format: date
sessions
required
integer
<= 9007199254740991
total
required
integer
<= 9007199254740991
dataState
required

zero when the window totals zero, observed otherwise. It is never how missing or unavailable data is represented — that is what the 409 codes are for.

string
Allowed values: observed zero
provenance
required
object
workspaceId
required
string
/^[A-Za-z0-9_-]{1,128}$/
connectionId
required
string
/^[A-Za-z0-9_-]{1,128}$/
propertyId
required
string
/^[1-9][0-9]{0,19}$/
timezone
required

IANA timezone of the property, e.g. Europe/Oslo.

string
>= 1 characters <= 100 characters
metricDefinition
required

The canonical definition, embedded in every result.

object
id
required
string
Allowed value: ga4.sessions
version
required
integer
Allowed value: 1
providerMetric
required
string
Allowed value: sessions
dimensions
required
Array<string>
>= 1 items <= 1 items
definition
required
string
Allowed value: Sessions that began on the property, as reported by the GA4 Data API sessions metric with the date dimension. This is the provider metric, not a reconstructed session_start event count.
aggregation
required
string
Allowed value: sum
timezone
required

Dates are the property’s calendar dates, never UTC-shifted.

string
Allowed value: property
privacy
required
object
fields
required
containsUserIdentifiers
required
boolean
sourceUrl
required
string format: uri
Allowed value: https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema
window
required
object
startDate
required
string format: date
endDate
required
string format: date
dataThrough
required
string format: date
source
required
string
Allowed value: ga4_data_api
completeness
required

Always complete in a 200 — an incomplete window is a 409, so this field can be relied on rather than checked.

string
Allowed value: complete
reconciliation
required

The product does not re-derive these numbers from a second source. Stated on every result rather than assumed.

string
Allowed value: not_independently_reconciled
freshness
required
object
oldestExtractedAt
required
string format: date-time
newestExtractedAt
required
string format: date-time
stale
required

True when the oldest snapshot is older than thresholdHours.

boolean
thresholdHours
required
integer
Allowed value: 30
flags
required

Always includes provider_may_revise_recent_data and not_independently_reconciled; adds stale_source_snapshot when freshness.stale is true. Surface these wherever the number is shown.

snapshots
required

The exact snapshot each day came from. Two results citing the same runId, extractionSeq and extractedAt for a date are reading the same publication — which is how a spreadsheet, a REST caller and an MCP client are shown to agree on more than a matching total. The source timestamp is selected from the head’s matching immutable sync run and must agree with every returned ClickHouse row; disagreement fails closed rather than returning provenance that cannot be vouched for.

Array<object>
>= 1 items <= 31 items
object
date
required
string format: date
runId
required
string
/^[A-Za-z0-9_-]{1,128}$/
extractionSeq
required
integer
>= 1 <= 9007199254740991
publishedAt
required
string format: date-time
extractedAt
required

Immutable extraction time from the matching source sync run, validated against analytics rows.

string format: date-time

invalid_json — the body is absent, not valid JSON, or not valid UTF-8.

invalid_query — the body is not a supported metric query (unknown field, malformed date, window outside 1–31 days, a metric or dimension other than ga4.sessions by date), or the URL carried a query delimiter, including a bare ?.

object
error
required
object
code
required
string
message
required
string
error
object
code
Allowed values: invalid_json invalid_query

unauthorized — missing, unknown, expired or revoked key.

object
error
required
object
code
required
string
message
required
string
error
object
code
Allowed value: unauthorized
WWW-Authenticate
required
string
Allowed value: Bearer

forbidden — the body’s workspaceId is not the key’s workspace, or the key lacks query:read.

object
error
required
object
code
required
string
message
required
string
error
object
code
Allowed value: forbidden

connection_unavailable — no active connection matches this workspace, connection and property, or it was disconnected mid-read.

object
error
required
object
code
required
string
message
required
string
error
object
code
Allowed value: connection_unavailable

method_not_allowed — Allow names the method this route accepts.

object
error
required
object
code
required
string
message
required
string
error
object
code
Allowed value: method_not_allowed
Allow
required
string
Allowed value: POST

data_not_ready when nothing in the window is published, data_incomplete when some days are; both name the missing dates so a caller can narrow the window or wait. timezone_conflict means published dates use different property timezones: re-sync every requested date using the property’s current timezone. No analytics read occurs for that conflict, and it does not include missingDates.

One of:

The two missing-publication 409 forms; timezone_conflict has no missingDates. This is a separate closed object because composing Error with allOf would reject missingDates under Error.properties.error.additionalProperties.

object
error
required
object
code
required
string
Allowed values: data_not_ready data_incomplete
message
required
string
missingDates
required
Array<string>
>= 1 items <= 31 items unique items
Examples
{
"error": {
"code": "data_incomplete",
"message": "Complete data is not available for every requested day.",
"missingDates": [
"2026-09-03",
"2026-09-04"
]
}
}

request_too_large — REST bodies are capped at 4 KiB.

object
error
required
object
code
required
string
message
required
string
error
object
code
Allowed value: request_too_large

unsupported_media_type unless the body is application/json, or unsupported_encoding for any Content-Encoding other than identity.

object
error
required
object
code
required
string
message
required
string
error
object
code
Allowed values: unsupported_media_type unsupported_encoding

query_unavailable — a backend is unreachable, or a stored row failed an integrity check. The boundary fails closed rather than returning a result it cannot vouch for, and never passes a database or provider message through.

auth_unavailable — the authorization store could not be reached. Pilot operations report this condition as automation_unavailable.

object
error
required
object
code
required
string
message
required
string
error
object
code
Allowed values: query_unavailable auth_unavailable