CLIENT API / V1 GOOGLE ANALYTICS 4

Prepare and reuse a stored GA4 report through the regular async worker

POST/sites/{site_id}/ga4/reports/{report_type}analytics:read, analytics:prepare

Requires analytics:read and site access. Accepts the same parameters as GET in a JSON object or in the query string, exclusively. source must be stored. Existing fresh reports return immediately; missing reports reuse or enqueue collection. Repeat GET with the same dates after completion. This does not change scheduled collection or backfill.

RequestPOST https://satelliteai.io/api/v1/sites/{site_id}/ga4/reports/{report_type}
Permissionanalytics:read, analytics:prepare
ResponseA single object: data is Ga4Report, or null when nothing is stored.
Operation IDprepareGa4Report

More context and worked examples are in the developer guide.

Example request

cURL · Bash
curl --fail-with-body --request POST \
  'https://satelliteai.io/api/v1/sites/123/ga4/reports/sessions_over_time' \
  -H 'Content-Type: application/json' \
  --data '{"start_date":"2026-01-01","end_date":"2026-10-25","limit":100}' \
  -H "Authorization: Bearer $SATELLITE_API_KEY"

Replace the example IDs with values returned by the discovery endpoints. Example values are placeholders, not real records.

Parameters

NameInTypeDescription
site_idrequiredpathintegerID from GET /sites.
min 1
report_typerequiredpathstring

Unknown or repeated query parameters return 400.

JSON request body

Send Content-Type: application/json. The request body is optional. Fields below describe the request; response fields follow separately.

JSON request fields
FieldTypeDescription
sourcestring
one of: stored
start_datestring (date)
end_datestring (date)
daysinteger
min 1 · max 365
limitintegerMaximum records per page applied to this request.
min 1 · max 100
offsetinteger
min 0 · max 100000
report_set_idinteger (int64)
min 1

Data dictionary

Stored report ready, or partial daily data with coverage metadata. Stored reports come from the canonical GA4 store. Missing intervals return a pending object; available reports can have an empty rows array. Use report_set_id to pin exact-range pages. Daily history and live Google results can change during pagination.

202: Collection pending. Response uses Ga4Report and Ga4Meta, including report_metadata.collection.jobs when work is queued.

[] marks an array element. nullable means the value can be null; treat it as unknown, not zero. always present means the key is always included in the object.

Fields in data
FieldTypeDescription
data.site_idintegeralways presentSatellite site ID (from GET /sites).
min 1
data.report_typestringalways present
data.sourcestringalways present
one of: stored, live
data.date_rangeobjectalways present
data.date_range.start_datestring (date)nullablealways present
data.date_range.end_datestring (date)nullablealways present
data.snapshot_datestring (date)nullablealways presentNull; canonical reports use explicit intervals and optional report_set_id.
data.fetched_atstring (date-time)nullablealways presentUTC publication or live fetch timestamp; null when no rows have been published.
data.stalebooleanalways presentTrue when the store identifies a pinned report as stale. False for live requests.
data.rowsarray of map of stringalways present
data.row_countintegeralways presentTotal matching published rows for stored; Google's matching rowCount for live. Consult coverage for missing dates.
min 0
data.row_count_is_totalbooleanalways presentTrue for the stored matching row count and live Google rowCount. Incomplete daily coverage does not imply complete interval data; consult state and missing_days.
data.report_metadataobjectnullablealways presentAllowlisted stored provenance/coverage or Google quality fields. Unrecorded metadata is unknown.
data.report_metadata.statestring
one of: ready, pending, partial, unsupported, empty_period
data.report_metadata.sourcestring
data.report_metadata.datasetstring
data.report_metadata.definition_versioninteger
data.report_metadata.binding_idinteger
data.report_metadata.connection_revisioninteger
data.report_metadata.timezonestring
data.report_metadata.startstring (date)
data.report_metadata.endstring (date)
data.report_metadata.currency_codestringnullable
data.report_metadata.report_set_idintegernullable
data.report_metadata.report_statestringnullable
data.report_metadata.publication_watermarkstringnullable
data.report_metadata.aggregationstring
data.report_metadata.missing_daysinteger
data.report_metadata.reasonstring
data.report_metadata.qualityarray of object
data.report_metadata.collectionobject
data.report_metadata.collection.statestring
data.report_metadata.collection.jobsarray of object
data.report_metadata.collection.jobs[].job_idstring
data.report_metadata.collection.jobs[].statusstring
data.report_metadata.collection.jobs[].status_urlstring
data.report_metadata.dataLossFromOtherRowboolean
data.report_metadata.subjectToThresholdingboolean
data.report_metadata.emptyReasonstring
data.report_metadata.currencyCodestring
data.report_metadata.timeZonestring
data.report_metadata.samplingMetadatasarray of object
data.report_metadata.samplingMetadatas[].samplesReadCountstring
data.report_metadata.samplingMetadatas[].samplingSpaceSizestring

Response metadata

Fields in meta
FieldTypeDescription
meta.request_idstringRequest identifier; also returned in X-Request-ID. Include it in support requests.
meta.api_versionstringAPI version that produced the response.
one of: v1
meta.limitintegeralways presentMaximum records per page applied to this request.
min 1 · max 100
meta.has_morebooleanalways presentAnother page is available within the API offset bound.
meta.next_cursorstringnullableOpaque cursor for the next page; send as cursor. Null on the last page.
meta.availabilitystringalways presentavailable when stored data exists; not_available when it does not.
one of: available, not_available
meta.billingobjectPresent for paid live SERP requests; replayed receipts describe the original debit, not an additional charge.
meta.billing.operationstringalways present
one of: client_api_serp_refresh
meta.billing.credits_chargedintegeralways present
min 0
meta.billing.transaction_idintegeralways present
meta.billing.replayedbooleanalways present
meta.statestring
one of: ready, pending, partial, unsupported, empty_period
meta.offsetintegeralways present
min 0 · max 100000
meta.next_offsetintegernullablealways presentNext allowed row offset, or null when traversal stops.
min 0 · max 100000
meta.offset_limit_reachedbooleanalways presentMore rows remain beyond the API offset cap; narrow the date range.

Error responses

Errors return {"error": {"code", "message", "request_id"}}. See error handling for retry guidance.

HTTPWhen
400Invalid parameters, incompatible date selectors, or unavailable report identity.
403Missing analytics:read or disabled integration.
404Missing or inaccessible site.
429Request or collection quota exceeded; honor Retry-After.
503Store or queue unavailable.