> ## Documentation Index
> Fetch the complete documentation index at: https://docs.interchange.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a reporting pipeline

> Read delivery into your application, export aggregates, or configure scheduled data delivery to your own storage.

You can use Apostra as the source for a dashboard, a daily reporting job, or an
agent that checks campaign performance. Start by deciding whether you need an
interactive aggregate, a downloadable aggregate, or a recurring data feed.

| Outcome                                                | Use                                                                | Who runs the schedule                       |
| ------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------- |
| Answer an agent's delivery question                    | v3 MCP `get_delivery` with explicit metrics, dimensions, and scope | Your client, when requested                 |
| Refresh a dashboard or warehouse table                 | v3 MCP delivery reads or v2 REST reporting reads                   | Your application                            |
| Download aggregate campaign data as CSV                | v2 REST reporting with `download=true`                             | Your application                            |
| Receive supported log-level data in your cloud storage | v2 Data Delivery credentials and outputs                           | Apostra's configured Data Delivery schedule |

These are different data products. A CSV aggregate is not a raw event feed, and
a notification is not a reporting export.

## 1. Prove access and choose the report

For MCP, call `get_status` and verify the active account. Inspect the current
`get_delivery` schema before choosing metrics and dimensions.

* A Buyer Account uses `report: "campaign_delivery"`.
* A Seller Account uses `report: "delivery"` for seller-reported delivery, or
  `report: "margin"` for its cumulative spread ledger.
* An integrated Media Company can also read `campaign_delivery` for its own
  supported advertiser, campaign, or media-buy scope. This does not grant a
  Seller credential general access to Buyer REST reporting.

For REST, use a credential authorized for the relevant Buyer API. A v3 MCP
OAuth token cannot be used on REST. See [Authentication](/v3/authentication).

## 2. Read a bounded delivery window

For a Buyer Account, call `get_delivery`:

```json theme={null}
{
  "report": "campaign_delivery",
  "metrics": ["impressions", "clicks", "spend", "ctr"],
  "dimensions": ["date", "campaign", "media_buy"],
  "range": {
    "startDate": "2026-09-01",
    "endDate": "2026-09-07"
  },
  "filters": { "campaignId": "CAMPAIGN_ID" },
  "limit": 25
}
```

Replace the campaign ID and dates with the scope you intend to read. Explicit
date ranges are inclusive UTC dates and support at most 90 days. Buyer campaign
delivery also supports `range: {"lifetime": true}`; a `packageId` filter requires
a bounded range instead. Use the
[buyer](/v2/setup/v3/buyer-workflows#7-query-campaign-delivery) or
[seller](/v2/setup/v3/seller-workflows#query-delivery-and-margin) reference for
the report available to your account.

Follow the returned pagination contract until all requested rows are read.
Preserve report type, account and resource scope, requested dimensions, returned
period, and the time of extraction with the results.

## 3. Preserve what the data means

Your consumer should carry coverage, warnings, finality, and unavailable values
alongside the numbers. Do not turn a missing source value into zero or describe
seller-reported delivery as independent buyer measurement. Finality alone is
not evidence that an amount is eligible for billing.

For Buyer campaign delivery, `totals` covers every matched row, not just the
current page. Do not add the repeated totals from successive pages. Mixed
currency results do not convert currencies: monetary totals can be unavailable
while counts remain usable. Keep each row's currency with its monetary values.

Seller delivery pages are live reads. A cursor continues the query but does not
freeze a historical snapshot. If your application needs a reproducible extract,
store the completed extract and its query metadata in your own system and
label when it was read.

## 4. Run a repeatable extraction job

For a daily dashboard or warehouse load, your worker can:

1. Load the account, report, requested dimensions, and last completed date
   window from its checkpoint.
2. Read each bounded window and all its pages into a staging destination.
3. Check warnings and coverage, then publish the completed window. Use a key
   containing its account, dimensions, date, and currency so a retry replaces
   the same data rather than appending duplicates.
4. Advance the checkpoint only after the destination has accepted the complete
   window.
5. Re-read a recent overlap window according to your source's correction and
   freshness needs. Retain when each extract was observed.

Delivery reaches reporting through supported seller webhooks, source polling,
and downstream aggregation. A successful API response is not a promise that a
seller has reported every event or that the result is real-time. Review the
[reporting data flow](/v2/guides/reporting-overview#how-delivery-data-flows) for
your sources. Buyer REST reporting is day-grain; an hourly job does not make
that endpoint an hourly delivery report.

## 5. Choose CSV export or scheduled cloud delivery

For a CSV aggregate, use the current v2 REST reporting contract:

```bash theme={null}
curl --fail-with-body \
  'https://api.interchange.io/api/v2/buyer/reporting/metrics?view=timeseries&days=7&download=true' \
  -H "Authorization: Bearer $APOSTRA_API_KEY"
```

This example requests the credential's available reporting scope. Add the
documented advertiser or campaign filters when the job should cover a narrower
scope. The response returns `downloadUrl`, `expiresAt`, `fileName`, and
`rowCount`. Fetch the file in the consuming service; the signed URL is a bearer
credential and must not appear in logs or public dashboards. See
[CSV export](/v2/guides/reporting-overview#csv-export-downloadtrue).

For a recurring cloud feed, follow [Data Delivery](/v2/guides/data-delivery):
grant the documented storage permissions, register an advertiser-scoped
credential, wait for its asynchronous validation, then attach outputs for the
supported data types and cadence. Confirm that objects arrive in your bucket
or container before treating the feed as working. Data Delivery uses v2
configuration today; it is not a generic v3 export tool.

Data Delivery credentials and outputs are full-replace arrays. Read the current
configuration and preserve entries you intend to keep before updating it.

## Use notifications to resume work

For a human operator, use the existing
[notification channels and inbox](/v2/guides/notifications). Registered external
buyer agents have separate
[machine-notification administration](/v2/setup/buyer-agent-credentials).
Use the documented event and delivery contract for that connection, and re-read
the referenced object before taking the next action.

Do not use authored notification subscriptions as a scheduler for this pipeline:
their schedule and condition triggers do not execute yet. A Slack incoming
webhook is a notification destination, not a machine-readable export of all
campaign changes. Your own scheduled poll or the supported Data Delivery
schedule is the working path for recurring extraction.

## Verify before connecting a dashboard

Test the consumer with empty data, an unavailable metric, mixed currencies, and
more than one page. Prove that rerunning a completed window does not duplicate
rows. Then read a known live campaign and compare its scope, period, and totals
with the same report in Apostra. Fixture tests verify your consumer; this live
comparison verifies access and the meaning of the selected report.
