Core concepts
Data freshness
Every number this API returns comes from ingested platform data, and ingestion can fail. /v1/sync is how you find out before your users do.
The failure this prevents
A connection breaks on a Tuesday. Nothing errors: the API keeps answering, the rows keep coming back, and every one of them is Monday. A dashboard reads it as spend falling off a cliff, somebody investigates a campaign that is fine, and the actual problem is an expired token.
The data to catch that exists and is one call away. An integration that reads it turns a silent wrong answer into a labelled partial one.
Reading sync state
curl "https://api.cresva.ai/v1/sync?brand_id=brd_8Kq2mR4xVn" \ -H "Authorization: Bearer $CRESVA_API_KEY"{ "brand_id": "brd_8Kq2mR4xVn", "data": [ { "platform": "meta", "last_attempt_at": "2026-07-31T06:00:00Z", "last_successful_sync_at": "2026-07-31T06:00:00Z", "data_fresh_as_of": "2026-07-30", "consecutive_failures": 0, "status": "ok", "last_error_code": null }, { "platform": "google", "last_attempt_at": "2026-07-31T06:00:00Z", "last_successful_sync_at": "2026-07-28T06:00:00Z", "data_fresh_as_of": "2026-07-27", "consecutive_failures": 3, "status": "failing", "last_error_code": "invalid_grant" } ], "meta": { "request_id": "req_01JQ8Z3M6WT4", "simulated": false }}Illustrative values. Google is shown failing on purpose: this is what a broken connection looks like.
What each field tells you
statusok, failing or never_synced. The last one means the platform is connected but has never delivered, which is a different problem from one that broke.data_fresh_as_oflast_successful_sync_atlast_attempt_at: a recent attempt and an old success is a connection that is trying and failing.consecutive_failureslast_error_codeinvalid_grant means the OAuth token needs reconnecting.Guarding a read
Compare the freshness date against the end of the range you asked for. If it is behind, say so beside the number rather than suppressing the number: partial data is still useful once it is labelled.
const { data: platforms } = await cresva.v1.getSyncState({ brand_id }); const stale = platforms.filter( (p) => p.status !== "ok" || p.data_fresh_as_of < requestedEndDate,); if (stale.length) { // Render the number AND the caveat. Suppressing the number entirely is // usually wrong: partial data is still data, as long as it is labelled. banner(`${stale.map((p) => p.platform).join(", ")} last delivered ${stale[0].data_fresh_as_of}`);}Cheap polling
/v1/syncis the cheapest call in the API. Poll it, and re-read metrics only whendata_fresh_as_ofhas moved.- That is also the answer to most rate-limit problems: an integration that re-reads a month of metrics every five minutes is asking the same question of unchanged data.
Forecasts and recommendations have their own answer
409 data_not_ready rather than a flat line. See Errors.