Skip to content

Date ranges and timezones

Range presets, explicit dates, the 400-day cap, half-hour timezones, compare, and which operations still bucket on UTC days.

article |4 min |Updated Sep 2026
On this page · 8 sections

The Convultra API and MCP server are in Beta. Fourteen of the 21 operations take a range, and you give it one of two ways: a preset, or explicit inclusive dates in a named timezone.

# A preset.
curl -s "https://data.convultra.com/v1/projects/acme.example/overview?range=30d" \
  -H "Authorization: Bearer sk_your_key_here"

# Or explicit inclusive dates, in a named timezone.
curl -s "https://data.convultra.com/v1/projects/acme.example/overview?start_date=2026-08-01&end_date=2026-08-31&timezone=Europe/London" \
  -H "Authorization: Bearer sk_your_key_here"

Presets

today, yesterday, 7d, 14d, 28d, 30d, 90d, 12mo, month (month to date) and last_month (the whole previous calendar month). The default is 30d.

Explicit dates

YYYY-MM-DD, inclusive at both ends. Give both start_date and end_date or neither; one alone is a 400. When both are present, range is ignored.

Timezone

timezone is an IANA name: Europe/London, America/New_York, Australia/Sydney. It defaults to the project’s own timezone, falling back to UTC. An unrecognized name is a 400 that tells you what a valid one looks like.

Limits

The maximum range is 400 days (about 13 months) in one request. Longer ranges are refused with 400 invalid_range; page through with narrower ranges for more history.

Half-hour zones are capped harder. Kolkata, Adelaide and Kathmandu sit at a fractional hour offset, which means their days cannot be re-cut from the hourly aggregates and must be read from raw events. Ranges over 90 days in such a zone are refused, with a message saying so. Narrow the range, or ask in UTC.

Compare

compare takes previous_period or previous_year. Only get_overview returns a comparison payload (previous and change blocks); on the other range endpoints the parameter is accepted and echoed in meta.range.compare but changes no figures.

Why the timezone matters

A project’s day boundaries follow its own timezone, not UTC. Google Ads reports in the ad account’s timezone; a Sydney client reconciling against it cannot use UTC days at all, because a UTC day cuts their afternoon in half. Setting the project timezone once, or passing timezone= per request, makes the figures line up with the ad platforms instead of drifting by hours.

The response always echoes the range and timezone it actually used:

"meta": {
  "range": {
    "start_date": "2026-08-13",
    "end_date": "2026-09-11",
    "timezone": "Europe/London"
  }
}

Read it rather than assuming. It is how you confirm that range=30d meant what you thought, and it is the first thing to check when a figure does not match a dashboard.

Operations whose buckets are still UTC

Four operations honor the start and end days of your range but bucket and bound internally on UTC days, regardless of the timezone you pass, because their underlying queries do not take a timezone yet:

  • get_event_timeseries
  • get_funnel
  • get_attribution
  • get_recovery

Nothing in the API pretends otherwise, and the MCP tool descriptions say so too. Everywhere else, including overview, timeseries, breakdown, conversions and delivery, the requested timezone decides the day boundaries.

  • granularity=hour on get_timeseries requires a range of 7 days or fewer, and spend is unavailable at hourly granularity.
  • Week and month buckets that extend past the requested range carry partial: true.
  • Delivery rows are dated by when the attempt was logged, shortly after the conversion, so a range edge can put a conversion and its delivery on different days.

See API operations for the full list of traps and API errors for invalid_range.

Next in Developers API errors →