Skip to main content
Buyers see what ran from the delivery your sales agent reports. Apostra gets it one of two ways: your agent pushes each report to Apostra, or Apostra reads it from your agent’s get_media_buy_delivery. This page covers both, the report your agent has to send, how Apostra answers it, and how to check what Apostra received for a media buy.

How Apostra gets your delivery

Your products decide it. Each product can declare reporting_capabilities.supports_webhooks in get_products. Apostra does not read reporting files from your own storage, so there is no bucket or file option. To send reports, push them. To have Apostra read them, declare supports_webhooks: false and answer get_media_buy_delivery. Certification judges the choice you make. See Reports arrive on time and the delivery report format finding.

Push reports to Apostra

When Apostra books on your agent, create_media_buy carries a reporting_webhook with the url to post reports to. Post to that URL exactly as it was sent, and sign every request. An unsigned or wrongly signed report gets 401 and is not read. See Signing the webhooks you send us.

Send the AdCP envelope

From AdCP 3.1, a delivery report is an MCP webhook envelope with task_type: "media_buy_delivery" and the report under result:
AdCP defines the shape, in media-buy/media-buy-delivery-webhook-result.json for your release. Apostra checks it against every AdCP release from 3.1 that it bundles, because a delivery webhook does not say which release it follows, and refuses it only when none of them accepts it. These fields are required: Send by_package on every entry. When you cannot split delivery by package, send an empty array. Leaving it out is a 400. Extra fields are kept, but they never stand in for a required one: by_day does not replace by_package. An AdCP 3.0 report, with media_buy_deliveries at the top level and no envelope, is still accepted so your reporting keeps working. It shows as a miss in the delivery report format finding. See Delivery reports.

Say which days the delivery is for

Send daily_breakdown on every entry, with one item per day and its date as YYYY-MM-DD, so Apostra can record each day. A report whose reporting_period is a single day names that day itself. Totals over several days with no daily_breakdown get a 200, but Apostra does not record them, because it cannot tell which day they belong to. Report a day after it has ended. A report for a day still in progress is acknowledged, but Apostra keeps it only as provisional figures for the buy. It is not recorded as that day’s delivery, and package figures wait for the closed day’s report. A period that ends at the next midnight and lasts 23 to 25 hours is open until that end. Any other period is open until 25 hours after its start. Report only what you observed. A day, package or source you have no figures for is not a zero, so leave it out rather than sending 0. Report spend in the currency the buy was booked in. A report in another currency is still recorded, but Apostra cannot book its spend.

How Apostra answers

Every report Apostra refuses is in your agent’s webhook results, with the first failing field.

Correct a report

To correct a figure, send the cumulative-to-date report again with the right value. Apostra keeps the latest report for each reporting day, media buy and source, so a re-sent report replaces your own earlier one for that day. It does not replace another source’s report for the same buy and day. A retry after a 503 therefore never counts twice.

When Apostra reads your delivery

If your products declare supports_webhooks: false, Apostra calls your get_media_buy_delivery for each live buy twice a day, at 02:00 and 14:00 UTC, once the buy has delivery to read. Right after a buy is created it reads more often while it waits for the first usable delivery.
  • Reads that return nothing usable. When a read comes back empty, or for an active buy has no daily_breakdown yet, Apostra reads again soon after, on a backoff that grows from seconds to an hour. It makes six reads in all for that slot, then waits for the next one.
  • After a buy completes. Apostra keeps reading it twice a day for seven days, to pick up late or revised reporting, and then stops.
  • The schedule is fixed. The frequencies a product declares in reporting_capabilities do not change when Apostra reads you. They set what certification expects.
  • Delivery by property is asked for only when you declare it. When every product on a buy declares supports_property_breakdown in reporting_capabilities, the read also carries reporting_dimensions.property with a limit of 250 rows per package. Answer it with by_property on every package, with by_property_truncated and by_property_suppressed. A package that comes back without them counts in the property delivery finding.
  • The reply must be valid AdCP. Apostra checks it against the AdCP get_media_buy_delivery response. Each by_package item needs package_id, spend, pricing_model, rate and currency. A reply that fails counts in valid responses.
When your Storefront sells Google Ad Manager (GAM) inventory through the sales agent Apostra runs for you, that agent reports your delivery from GAM in two ways: provisional figures about every 15 minutes while a buy runs, shown in Campaign Pulse, and daily figures read twice a day. See How often Apostra reads GAM delivery. Each daily read runs a new GAM report, so nothing is cached between those reads.

Impressions and clicks are filtered for invalid traffic

Delivery impressions and clicks are GAM’s ad-server counts, AD_SERVER_IMPRESSIONS and AD_SERVER_CLICKS, which already leave out the traffic GAM judged invalid. Google says Ad Manager “discards impressions and clicks that are considered invalid” (how Ad Manager counts impressions and clicks), and that its metric totals are net of General Invalid Traffic (GIVT) filtration and some Sophisticated Invalid Traffic (SIVT) filtering techniques (Ad Manager’s invalid traffic methodology). These filtered counts are the impressions and clicks buyers see. Your products also report two AdCP vendor metrics from google.com: unfiltered_impressions and unfiltered_clicks. They are GAM’s counts before invalid-traffic filtering (AD_SERVER_UNFILTERED_IMPRESSIONS and AD_SERVER_UNFILTERED_CLICKS), reported beside the filtered counts for comparison. Each product lists them in reporting_capabilities.vendor_metrics, and each package’s delivery carries them in vendor_metric_values. The gap between the unfiltered and filtered counts is the traffic GAM judged invalid. The ad-server delivery check in certification compares our tracker with unfiltered_impressions.

How often Apostra reads GAM delivery

Buyers get your GAM delivery in two forms: provisional figures within minutes, and daily figures once GAM has counted each day. Provisional figures, about every 15 minutes. While a buy runs, the sales agent re-reads the delivery counts of your live GAM line items, those delivering or ready to deliver, about every 15 minutes. It reads the counts GAM keeps on each line item rather than running a report, so it uses none of your report quota. Apostra reads them from the agent every 5 minutes, as each package’s snapshot (get_media_buys with include_snapshot), so a new count reaches buyers within about 5 minutes. A buy is read this way from the start of its flight for as long as the agent reports it active. You don’t need to set anything up. The snapshot holds each package’s running totals since the flight started: impressions, clicks and spend. Buyers see it in Campaign Pulse, labelled provisional. It is not final and not billable, and it is kept apart from the daily figures: it never replaces or adds to them. The two come from different GAM reads, and GAM can still revise its counts, so the daily figures for a day can differ from the provisional ones buyers saw during it. Daily figures, twice a day. GAM needs about four hours to count delivery. So your GAM products declare expected_delay_minutes of 240, or more if you set a longer delay, report daily in your network’s timezone, and declare supports_webhooks: false. Apostra therefore reads your delivery on the schedule in When Apostra reads your delivery:
  • Twice a day. Apostra reads each live buy at 02:00 and 14:00 UTC.
  • Until the first figures land. Until a buy has its first usable delivery, Apostra reads again on a backoff that grows to an hour, up to six reads for each slot.
  • For seven days after a buy completes. Apostra keeps reading twice a day, to pick up GAM’s revisions, and then stops.
Each read brings in what GAM had counted by then, about four hours behind, so buyers see a day’s figures fill in over the reads during and after it. How long before buyers see the whole day depends on your network’s timezone, because GAM counts a day in it: the day is whole at the first read at least four hours after it ends. For a network in the Americas or Europe, that is usually the 14:00 UTC read the next day. For one in Asia or Australia, it is the 02:00 UTC read the next day. To ask Apostra to read a buy again, use Ask Apostra to read again. GAM delivery is not synced by a separate reporting sync: Apostra reads it live, so a reporting sync with no runs on a GAM source is expected, not a fault.

Reporting receipts

A reporting receipt is read-only evidence of one report Apostra received for a buyer’s media buy, whether your agent pushed it or Apostra read it. It helps you confirm that a report arrived and see how Apostra handled it. It is not the buyer’s delivery result, a billing record, or a statement that reporting is final.

Read receipts

Call get_seller_reporting_receipts as a Seller Account:
buyerAccountId is the Buyer Account that owns the media buy. The tool opens the shared Media Buy Timeline Glance and returns the same data. You can read a media buy only if that buyer account booked it with you. Otherwise the tool answers NOT_FOUND, which does not say whether the buy exists. The buyer account also needs reporting status. A buyer account on the standard buyer profile, which new buyer accounts get by default, has it, and so do buyers in the V3 beta. A buyer account on an earlier profile does not, and for its media buys the tool answers FEATURE_NOT_ENABLED. You cannot change a buyer’s profile. The result holds:
  • receipts: one item per report, newest first. Each has a receiptId you can match to the report your agent sent, receivedAt, and a transport: a report your agent pushed is storefront_source_push, and a read Apostra made is storefront_route_poll. The values webhook, poll and bucket come from older reporting paths.
  • acceptance on each receipt: a state and, when there is one, a reason with a code, the first error your source reported as sourceCode, and its message.
  • receivedTotals and receivedDailyTotals on each receipt: the values that arrived in that report, exactly as your report expressed them. They cover spend, impressions, clicks, videoCompletions, views, conversions, leads and currency, as strings so you can compare them without losing precision. A later correction does not rewrite them.
  • computedDailyTotals: Apostra’s current value for each day and package, with the time it was computedAt. A later report can correct a computed day, so these can differ from an earlier receipt. Use the receipt to trace the input and the computed totals to see Apostra’s present view.
  • canonical: the current reporting status for the media buy. See Reliable Reporting registration. Reading it does not request a new report.

Receipt states

A state says what happened to that receipt. It does not say that every required report arrived, that coverage is complete, or that the media buy is final, and it is not proof that spend is billable.

Limits

A result is bounded so it is never mistaken for a reporting export. It returns the newest five receipts, up to fourteen received daily totals for each receipt, and the newest thirty-one computed daily totals. When more exists, the matching flag is true: receiptsTruncated, receivedDailyTotalsTruncated on the receipt, or computedDailyTotalsTruncated. In the Timeline, the Reporting receipts section shows three receipts at a time and lets you page through the ones returned. It also has controls for the two requests below.

Ask Apostra to read again

After you read receipts, request_seller_reporting_update asks Apostra to read a media buy’s reporting again. It never calls your agent itself: Apostra’s scheduler makes the read. It takes the same accountId, mediaBuyId and buyerAccountId, and the same access rules, as the receipts read.
  • refresh asks for the next read of reporting periods that have ended and are not already queued. At most 25 of your refresh requests can be waiting at one time. The result gives queuedReportingItemCount and that limit as requestLimit.
  • replay asks for a read of a range of days. Add "action": { "kind": "replay", "startDay": "2026-11-01", "endDay": "2026-11-07" }. The range is 1 to 31 calendar days, and a request covers at most 25 reporting items. Apostra accepts at most two replay requests from you in any 24 hours. A third comes back with rateLimited: true and nothing queued.
A replay never changes a day that is already final. Those days come back in refusedFinalDays. Items already waiting for a read are counted in alreadyQueuedReportingItemCount and are not queued again. Both requests act on the reporting items Apostra has recorded for the buy. If it has recorded none, queuedReportingItemCount is 0. Neither changes buyer permissions or billing.