Back to Blogengineering

Keeping profit current when Meta rewrites the past

Attribution keeps settling for weeks. Pluto rechecks 28 days of Meta data so spend, ROAS, and profit catch up, not a one-shot import that freezes the wrong number.

Timeline showing frequent Meta syncs and a 28-day reporting settlement boundary

Yesterday's Meta report is not necessarily yesterday's final Meta report. Spend usually arrives quickly, while attributed purchases and purchase value can continue to move as events are processed and credited to earlier ad interactions.

If an analytics product imports each date once and never re-fetches it, the warehouse can preserve an early version of the truth forever. Spend stays in place, later conversions never arrive, and ROAS remains lower than the figure Meta eventually reports.

What Meta documents today#

As of July 12, 2026, Meta's Marketing API Insights guidance says that Insights refresh approximately every fifteen minutes, may continue updating for a couple of days after an ad has completed, and do not change after 28 days of being reported.

Meta also changed API attribution behavior on June 10, 2025. Attributed values now follow the attribution settings configured at the ad-set level, matching Ads Manager behavior. For standard attribution, Meta currently documents one-day or seven-day click-through settings and a one-day view-through setting.

Ads Manager can expose additional comparison views in some campaign contexts, including 28-day click reporting. That is separate from the reason Pluto re-fetches 28 days of data.

Settlement horizon is not attribution window#

These two ideas are easy to mix up:

  • An attribution window determines whether a conversion can be credited to an ad interaction.
  • A settlement horizon describes how far back an analytics pipeline is willing to recheck previously imported reports.

Pluto's 28-day window is the second. It is a conservative reconciliation boundary based on Meta's statement that Insights do not change after 28 days. It is not a claim that every campaign uses 28-day attribution.

Why a one-time import produces wrong ROAS#

Imagine that Monday's ads spent $1,000 and Meta initially reports $2,000 in attributed purchase value. A reporting pipeline imports the day on Tuesday and calculates a ROAS of 2.0.

Additional eligible purchases are processed later, and Meta revises Monday's attributed value to $2,300. Ads Manager now shows a ROAS of 2.3. A warehouse that never re-fetches Monday still shows 2.0, even though every calculation in the warehouse is internally correct.

The error is not in the ROAS formula. It is in treating an unsettled upstream report as immutable.

Pluto uses three sync windows#

The Meta sync engine gives different work different schedules:

  • Initial backfill: 365 days when a merchant first connects an account.
  • Incremental sync: today and yesterday, queued every fifteen minutes.
  • Daily reconciliation: the trailing 28 days, fetched once per day.

The short window keeps current spend and conversions moving without repeatedly requesting a full year. The daily window revisits dates that Meta may still revise. The initial backfill provides useful history without making every normal sync carry that cost.

New versions replace old versions#

Re-fetching only helps if storage handles revisions correctly. Pluto writes each daily ad-level result with a fetch timestamp into a ClickHouse ReplacingMergeTree. The logical key identifies the account, campaign, ad set, ad, and date; the fetch timestamp identifies the version.

When Meta revises a date, Pluto inserts a newer version of the same fact. Queries use FINAL to read the latest version rather than summing both. That makes the process idempotent: re-running a window repairs the stored view instead of double-counting it.

Fresh and settled are different promises#

A successful sync means Pluto has read Meta recently. It does not mean Meta's newest conversion data is final. That distinction should be visible in both engineering and product language.

We use frequent incremental syncs for freshness and repeated historical syncs for settlement. Together they produce a report that updates quickly without pretending the first number received can never change.

The practical rule#

Mutable reporting APIs should be modeled as mutable. Store versions, recheck the period the provider says may still change, and keep attribution settings separate from reconciliation policy.

For Meta, Pluto currently uses a 28-day re-fetch horizon because it matches the documented boundary after which Insights stop changing. If Meta changes that guarantee, the window should change with it.

Questions or sharp takes: join Discord or email hello@plutoprofit.com.